<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Baransel</title>
    <description>The latest articles on Forem by Baransel (@baransel).</description>
    <link>https://forem.com/baransel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F204050%2F368aac35-b146-4624-912a-af923d6ee1de.JPG</url>
      <title>Forem: Baransel</title>
      <link>https://forem.com/baransel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/baransel"/>
    <language>en</language>
    <item>
      <title>Monitor Any Solana Wallet in Real-Time with Node.js</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Mon, 23 Mar 2026 20:38:19 +0000</pubDate>
      <link>https://forem.com/baransel/monitor-any-solana-wallet-in-real-time-with-nodejs-4i3p</link>
      <guid>https://forem.com/baransel/monitor-any-solana-wallet-in-real-time-with-nodejs-4i3p</guid>
      <description>&lt;p&gt;I spent way too long polling &lt;code&gt;getSignaturesForAddress&lt;/code&gt; in a loop. Every 3 seconds, hitting the RPC, checking if there's a new transaction. It worked, but it was ugly and slow.&lt;/p&gt;

&lt;p&gt;Then I found out you can just &lt;strong&gt;subscribe&lt;/strong&gt; to account changes over WebSocket. No polling. No wasted requests. You get notified the moment something happens.&lt;/p&gt;

&lt;p&gt;Here's exactly how I do it now.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Set Up a WebSocket Connection
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@solana/web3.js&lt;/code&gt; has built-in WebSocket support. You don't need a separate library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PublicKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@solana/web3.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.mainnet-beta.solana.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;wsEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wss://api.mainnet-beta.solana.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;commitment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirmed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's your entry point. The &lt;code&gt;wsEndpoint&lt;/code&gt; is what makes real-time tracking possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Subscribe to Account Changes
&lt;/h2&gt;

&lt;p&gt;Pick any wallet address and subscribe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TARGET_WALLET_ADDRESS_HERE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onAccountChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accountInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SOL balance changed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accountInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lamports&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SOL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Slot:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time that wallet's SOL balance changes, your callback fires. Immediately. No delay.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Track Token Movements Too
&lt;/h2&gt;

&lt;p&gt;SOL changes are easy. But most of the interesting stuff happens with SPL tokens. For that, you subscribe to &lt;strong&gt;token accounts&lt;/strong&gt; instead.&lt;/p&gt;

&lt;p&gt;First, find all token accounts for a wallet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TOKEN_PROGRAM_ID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@solana/spl-token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenAccounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTokenAccountsByOwner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;programId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TOKEN_PROGRAM_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pubkey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;tokenAccounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onAccountChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Token account data changed — parse the new balance&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readBigUInt64LE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Token account &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBase58&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt; new raw amount: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you're watching every token account that wallet owns. When they buy, sell, or receive tokens — you see it.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Watch for New Transactions with onLogs
&lt;/h2&gt;

&lt;p&gt;Sometimes you don't care about balance changes. You want to see &lt;strong&gt;every transaction&lt;/strong&gt; a wallet touches. &lt;code&gt;onLogs&lt;/code&gt; is perfect for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onLogs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New tx:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Logs:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Transaction failed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirmed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fires for every transaction involving that wallet. You get the signature and the program logs right away — no extra RPC call needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Don't Forget to Clean Up
&lt;/h2&gt;

&lt;p&gt;WebSocket subscriptions stay open until you close them. If you're tracking multiple wallets, this matters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Remove a subscription when you're done&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeAccountChangeListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;subId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I learned this the hard way. Left 200+ subscriptions running and my RPC provider wasn't happy.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Handle Disconnections
&lt;/h2&gt;

&lt;p&gt;WebSockets drop. It happens. Your code needs to handle it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createMonitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;walletAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.mainnet-beta.solana.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;wsEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wss://api.mainnet-beta.solana.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;commitment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirmed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onAccountChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Balance:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lamports&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SOL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Reconnect on close&lt;/span&gt;
    &lt;span class="nx"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_rpcWebSocket&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WebSocket closed. Reconnecting...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not the prettiest code. But it works, and that's what matters when you're tracking wallets at 3am.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Putting It All Together
&lt;/h2&gt;

&lt;p&gt;Here's a minimal but complete wallet monitor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PublicKey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@solana/web3.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TOKEN_PROGRAM_ID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@solana/spl-token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RPC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.mainnet-beta.solana.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wss://api.mainnet-beta.solana.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;monitorWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RPC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;wsEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;commitment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirmed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Watch SOL balance&lt;/span&gt;
  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onAccountChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[SOL] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lamports&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e9&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; SOL`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Watch all token accounts&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTokenAccountsByOwner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;programId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TOKEN_PROGRAM_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pubkey&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onAccountChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[TOKEN] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pubkey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBase58&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt; changed`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Watch transaction logs&lt;/span&gt;
  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onLogs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[TX] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirmed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Monitoring &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;monitorWallet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WALLET_ADDRESS_HERE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it. Point it at any wallet. You'll see every SOL change, token change, and transaction as it happens.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Use This vs Yellowstone gRPC
&lt;/h2&gt;

&lt;p&gt;If you're tracking a handful of wallets, WebSocket subscriptions are perfect. Simple, built-in, no extra dependencies.&lt;/p&gt;

&lt;p&gt;If you're tracking hundreds of wallets or need to filter by program, &lt;strong&gt;Yellowstone gRPC&lt;/strong&gt; is better — I covered that in my &lt;a href="https://baransel.dev/post/parse-solana-transactions-efficiently/" rel="noopener noreferrer"&gt;transaction parsing post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pick the right tool for the job. For most wallet monitoring use cases, what I showed here is more than enough.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>blockchain</category>
      <category>web3</category>
      <category>javascript</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Sun, 08 Mar 2026 17:35:35 +0000</pubDate>
      <link>https://forem.com/baransel/-hi8</link>
      <guid>https://forem.com/baransel/-hi8</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/baransel" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F204050%2F368aac35-b146-4624-912a-af923d6ee1de.JPG" alt="baransel"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/baransel/i-built-a-pomodoro-app-heres-why-3dne" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;I Built a Pomodoro App. Here's Why.&lt;/h2&gt;
      &lt;h3&gt;Baransel ・ Mar 8&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#learning&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#showdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>learning</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Built a Pomodoro App. Here's Why.</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Sun, 08 Mar 2026 17:35:17 +0000</pubDate>
      <link>https://forem.com/baransel/i-built-a-pomodoro-app-heres-why-3dne</link>
      <guid>https://forem.com/baransel/i-built-a-pomodoro-app-heres-why-3dne</guid>
      <description>&lt;p&gt;I've tried every Pomodoro app out there. Seriously. Forest, Focus Keeper, Be Focused, random ones with 4.8 stars and 12 reviews. They all did the same thing — a timer that counts down from 25 minutes. Some of them did it with trees. Some with pixel art. Some with way too many settings.&lt;/p&gt;

&lt;p&gt;None of them felt right.&lt;/p&gt;

&lt;p&gt;So I built my own. It's called &lt;strong&gt;Foku&lt;/strong&gt;, and it's now live on the &lt;a href="https://apps.apple.com/app/id6760143159" rel="noopener noreferrer"&gt;App Store&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem With Most Focus Apps
&lt;/h2&gt;

&lt;p&gt;Most Pomodoro apps fall into two categories: either they're too simple (literally just a countdown timer with no context), or they're packed with features you'll never touch. Gamification, social leaderboards, ambient sounds, meditation modes — it's like they forgot the whole point is to help you focus.&lt;/p&gt;

&lt;p&gt;I wanted something in between. A timer that looks clean, works fast, and actually shows me whether I'm being consistent over time. That's it. Nothing fancy.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Foku Does
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Foku is a focus timer with just enough features to be useful.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's the core of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Customizable Pomodoro sessions&lt;/strong&gt; — 45-minute default because 25 never felt like enough for deep coding sessions. You can change it to whatever works for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Activity and Dynamic Island&lt;/strong&gt; — start a session and it shows up on your lock screen. No need to open the app to check how much time is left.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Home screen widget&lt;/strong&gt; — see your daily focus time, completed sessions, and current streak without opening anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt; — daily, weekly, monthly charts. I wanted to see patterns in when I'm most productive, not just count tomatoes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Activity grid&lt;/strong&gt; — think GitHub's contribution graph but for focus sessions. Five weeks of visual consistency tracking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple color themes&lt;/strong&gt; — because staring at the same screen for hours means it should at least look good.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs locally on your device. No accounts, no cloud sync, no data collection. Your focus data stays on your phone.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Didn't Just Use an Existing App
&lt;/h2&gt;

&lt;p&gt;Two reasons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, I wanted to learn.&lt;/strong&gt; Building a native iOS app with Live Activities, widgets, and Dynamic Island support taught me things I couldn't have picked up from tutorials alone. There's a difference between reading about WidgetKit and actually debugging why your widget won't refresh.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second, I had opinions about how it should work.&lt;/strong&gt; I don't want a 25-minute default — I want 45. I don't want achievement badges — I want a streak counter. I don't want ambient rain sounds — I want silence and a clean screen. Every existing app came with someone else's opinions baked in.&lt;/p&gt;

&lt;p&gt;Building your own means every design choice is intentional. That matters more than it sounds.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tech Behind It
&lt;/h2&gt;

&lt;p&gt;Foku runs on SwiftUI. The timer uses background tasks and local notifications to work even when the app isn't in the foreground. Live Activities use ActivityKit, and the widgets are built with WidgetKit.&lt;/p&gt;

&lt;p&gt;The data layer is entirely local — no backend, no API calls. Core Data handles session storage, and the analytics are computed on-device.&lt;/p&gt;

&lt;p&gt;I kept the architecture simple on purpose. A focus timer doesn't need a microservices backend. It needs to start fast, count accurately, and not drain your battery.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Building a "Simple" App Actually Takes
&lt;/h2&gt;

&lt;p&gt;Here's what nobody tells you about shipping a "simple" app: it's not simple.&lt;/p&gt;

&lt;p&gt;The timer itself took a day. Everything around it took weeks. App Store screenshots, privacy policies, subscription setup, handling edge cases like "what happens when the user kills the app mid-session," testing on different devices, making the widget actually look good at every size.&lt;/p&gt;

&lt;p&gt;The 80/20 rule is real. The last 20% of polish takes 80% of the time. But that polish is what separates an app you open once from one you actually keep.&lt;/p&gt;




&lt;h2&gt;
  
  
  It's Free (Mostly)
&lt;/h2&gt;

&lt;p&gt;The basic timer is completely free. No ads, no time limits, no "watch a video to unlock your third session."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Foku Pro&lt;/strong&gt; unlocks full analytics with charts and custom color themes. That's $2.99/month or $19.99/year. I priced it low because I know what it's like to be a student or a developer trying to stay focused without spending a fortune on productivity tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I'm actively working on Foku. There's a lot I want to add — better analytics, session categories, maybe Shortcuts integration. But I'm being deliberate about it. Every feature has to earn its place.&lt;/p&gt;

&lt;p&gt;If you want to try it, here's the link: &lt;a href="https://apps.apple.com/app/id6760143159" rel="noopener noreferrer"&gt;Foku on the App Store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It works on iPhone, iPad, Mac (Apple Silicon), and even Vision Pro. Give it a shot and let me know what you think.&lt;/p&gt;

&lt;p&gt;I built this for myself. Turns out that's the best way to build something others actually want to use too.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>learning</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How I Stay Productive as a Solo Developer</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Sun, 01 Mar 2026 19:21:11 +0000</pubDate>
      <link>https://forem.com/baransel/how-i-stay-productive-as-a-solo-developer-1n1e</link>
      <guid>https://forem.com/baransel/how-i-stay-productive-as-a-solo-developer-1n1e</guid>
      <description>&lt;p&gt;Working alone is great until you realize nobody is going to tell you what to do next. No standup. No sprint board someone else filled in. No manager pinging you on Slack asking for an update. It's just you, your editor, and a list of things that somehow keeps growing.&lt;/p&gt;

&lt;p&gt;I've been working solo on projects for a while now, and I won't pretend I have it all figured out. But I've found a few things that consistently help me stay on track without burning out or staring at my screen doing nothing for three hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  I write down what I'm going to do before I open my editor
&lt;/h2&gt;

&lt;p&gt;This sounds basic but it changed everything for me. Before I even touch code, I open a note and write down 2 or 3 things I want to finish today. Not a backlog. Not a Jira board. Just a few lines.&lt;/p&gt;

&lt;p&gt;Something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fix the login redirect bug&lt;/li&gt;
&lt;li&gt;Add the settings page layout&lt;/li&gt;
&lt;li&gt;Write tests for the API endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. When I don't do this, I end up jumping between tasks, half-finishing things, and feeling like I did nothing at the end of the day.&lt;/p&gt;




&lt;h2&gt;
  
  
  Small tasks first
&lt;/h2&gt;

&lt;p&gt;I used to try and start with the hardest thing on my list because that's what every productivity blog tells you. "Eat the frog" and all that.&lt;/p&gt;

&lt;p&gt;Doesn't work for me. If I start with something hard, I get stuck early and lose momentum. What actually works is knocking out one or two small tasks first. It gets me moving. By the time I hit the harder stuff, I'm already in the zone and it doesn't feel as bad.&lt;/p&gt;




&lt;h2&gt;
  
  
  I don't code all day
&lt;/h2&gt;

&lt;p&gt;This was hard to accept at first. I used to think that if I wasn't coding for 8+ hours straight, I wasn't being productive. But honestly, my best work happens in focused blocks of 2 to 3 hours. After that, the quality drops and I start making dumb mistakes.&lt;/p&gt;

&lt;p&gt;So now I work in chunks. A few hours of deep work, then I step away. Go for a walk, eat something, go to the gym. When I come back I'm usually sharper and I can do another focused session.&lt;/p&gt;

&lt;p&gt;Trying to force 10 hours of coding is just lying to yourself. Half of those hours are you staring at the screen pretending to work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Music helps, but not always
&lt;/h2&gt;

&lt;p&gt;I know this is personal, but I can't code in silence. I need something in the background. Usually it's lo-fi, sometimes it's ambient stuff, sometimes I just put on a long playlist and forget about it.&lt;/p&gt;

&lt;p&gt;But if I'm doing something that requires real thinking, like designing a data model or debugging something weird, I turn everything off. Silence helps when the problem is hard. Music helps when the work is repetitive.&lt;/p&gt;




&lt;h2&gt;
  
  
  I batch similar tasks together
&lt;/h2&gt;

&lt;p&gt;Context switching kills productivity. If I'm writing frontend code, I try to finish all the frontend work before moving to the backend. If I'm fixing bugs, I fix all the bugs I can before switching to new features.&lt;/p&gt;

&lt;p&gt;Every time you jump between different types of work, your brain needs time to adjust. It feels small but it adds up fast. Batching similar tasks together saves me at least an hour a day, probably more.&lt;/p&gt;




&lt;h2&gt;
  
  
  I say no to most new ideas while I'm building something
&lt;/h2&gt;

&lt;p&gt;This one is tough because new ideas feel exciting and the thing you're currently building feels boring. But if you chase every new idea, you'll never finish anything.&lt;/p&gt;

&lt;p&gt;When I get a new idea while working on something, I write it down in a note and move on. That's it. I don't create a repo. I don't research the tech. I don't even think about it too much. I just write it down so I don't forget, and go back to what I was doing.&lt;/p&gt;

&lt;p&gt;Most of those ideas don't seem as exciting a week later anyway.&lt;/p&gt;




&lt;h2&gt;
  
  
  I track what I actually did, not just what I planned
&lt;/h2&gt;

&lt;p&gt;At the end of the day I quickly write down what I got done. Not in detail, just a quick list. This helps me see patterns over time. I notice which days I get the most done, what types of tasks I tend to avoid, and when I'm starting to burn out.&lt;/p&gt;

&lt;p&gt;It also feels good to look back at a week and see a list of things you actually shipped instead of just guessing.&lt;/p&gt;




&lt;h2&gt;
  
  
  It's not about discipline, it's about systems
&lt;/h2&gt;

&lt;p&gt;I don't think I'm more disciplined than anyone else. I just found a few small systems that work for me and I stick to them. The daily list, the small tasks first, the focused blocks, the batching.&lt;/p&gt;

&lt;p&gt;None of this is revolutionary. But doing it consistently is what makes the difference. Especially when you're working alone and there's nobody holding you accountable except yourself.&lt;/p&gt;

</description>
      <category>general</category>
    </item>
    <item>
      <title>Stop Overengineering Your Side Projects</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Sat, 21 Feb 2026 11:38:44 +0000</pubDate>
      <link>https://forem.com/baransel/stop-overengineering-your-side-projects-1a3c</link>
      <guid>https://forem.com/baransel/stop-overengineering-your-side-projects-1a3c</guid>
      <description>&lt;p&gt;I have a graveyard of unfinished projects. Seriously. If you looked at my old repos you'd find half-built dashboards, abandoned CLIs, and at least three "starter templates" that I spent weeks perfecting and never used for anything.&lt;/p&gt;

&lt;p&gt;The pattern was always the same. I'd get excited about an idea, spend two days setting up the perfect folder structure, add linting, CI, Docker, maybe even a design system. And by the time I was "ready to start building" I'd already lost interest.&lt;/p&gt;

&lt;p&gt;Sound familiar?&lt;/p&gt;




&lt;h2&gt;
  
  
  The trap is feeling productive
&lt;/h2&gt;

&lt;p&gt;Setting up tooling &lt;em&gt;feels&lt;/em&gt; like progress. You configure ESLint, set up Prettier, add path aliases, create a beautiful README, maybe even write a contributing guide. For a project that only you will ever touch.&lt;/p&gt;

&lt;p&gt;It's comfortable because it's familiar. You know how to do it. And it gives you that satisfying feeling of "doing things right."&lt;/p&gt;

&lt;p&gt;But you're not building anything yet.&lt;/p&gt;

&lt;p&gt;I've done this so many times that I started recognizing the pattern. The moment I catch myself spending more than 30 minutes on config for a side project, I know I'm just procrastinating.&lt;/p&gt;




&lt;h2&gt;
  
  
  What actually worked for me
&lt;/h2&gt;

&lt;p&gt;When I built &lt;a href="https://apps.apple.com/us/app/gymdose-supplement-tracker/id6756020237" rel="noopener noreferrer"&gt;GymDose&lt;/a&gt; I did the opposite of what I normally do. I didn't plan the architecture. I didn't set up a monorepo. I didn't even think about scalability.&lt;/p&gt;

&lt;p&gt;I just opened Flutter, created a screen, and started building the thing I needed.&lt;/p&gt;

&lt;p&gt;The first version looked rough. The state management was all over the place. I had hardcoded strings everywhere. But it &lt;em&gt;worked&lt;/em&gt;. I could open the app, tap my supplements, and close it. That was enough.&lt;/p&gt;

&lt;p&gt;And because it worked I kept using it. Because I kept using it I kept improving it. Small fixes here, a better layout there. Over a few months it turned into something I was actually proud of, and I eventually published it.&lt;/p&gt;

&lt;p&gt;None of that would've happened if I started with a "proper" architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  You don't need most of what you think you need
&lt;/h2&gt;

&lt;p&gt;For a side project you probably don't need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A monorepo setup&lt;/li&gt;
&lt;li&gt;Docker in development&lt;/li&gt;
&lt;li&gt;CI/CD pipelines (just deploy manually at first)&lt;/li&gt;
&lt;li&gt;Separate staging and production environments&lt;/li&gt;
&lt;li&gt;A custom component library&lt;/li&gt;
&lt;li&gt;100% test coverage&lt;/li&gt;
&lt;li&gt;TypeScript strict mode on day one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not saying these things are bad. They're great in the right context. But for a side project you're building alone on weekends? They're just overhead that slows you down before you even know if the idea is worth pursuing.&lt;/p&gt;

&lt;p&gt;You can always add them later. You almost never need them at the start.&lt;/p&gt;




&lt;h2&gt;
  
  
  The real goal is to find out if the idea works
&lt;/h2&gt;

&lt;p&gt;Side projects aren't about code quality. They're about answering one question: &lt;strong&gt;does this thing solve a problem?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If yes, you'll naturally clean up the code because you'll keep working on it. If no, you just saved yourself weeks of planning something that was never going to matter anyway.&lt;/p&gt;

&lt;p&gt;I wasted months building "proper" projects that nobody, including me, ever used. The one I actually shipped was the messiest one I ever started.&lt;/p&gt;




&lt;h2&gt;
  
  
  Some rules I try to follow now
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;One file is fine.&lt;/strong&gt; If you can build the first version in a single file, do it. Split later when it actually gets painful, not before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skip the abstractions.&lt;/strong&gt; Don't create a &lt;code&gt;utils/&lt;/code&gt; folder with three functions in it. Don't write a custom hook for something you use once. Copy-paste is completely fine for a prototype.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy the ugly version.&lt;/strong&gt; Put it out there. Use it yourself. Show it to one friend. The feedback from a working prototype is worth more than a month of planning in your head.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Give yourself a time limit.&lt;/strong&gt; I try to get something working in one weekend. If I can't get a usable version in two days, either the scope is too big or I'm overcomplicating it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't optimize what doesn't exist yet.&lt;/strong&gt; You can't improve something you haven't built. Ship first, optimize later. The bottleneck is almost never performance, it's the fact that the project doesn't exist yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  This isn't about writing bad code
&lt;/h2&gt;

&lt;p&gt;I want to be clear. I'm not saying write garbage and call it done. What I'm saying is &lt;strong&gt;lower the bar for starting&lt;/strong&gt; and raise it gradually as the project proves itself.&lt;/p&gt;

&lt;p&gt;The best code I've written came from projects that started messy and got cleaned up over time. Because by that point I actually understood the problem well enough to make good decisions, instead of guessing upfront.&lt;/p&gt;




&lt;h2&gt;
  
  
  Just build the thing
&lt;/h2&gt;

&lt;p&gt;If you have an idea sitting in your notes right now, here's what I'd do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your editor&lt;/li&gt;
&lt;li&gt;Create one file&lt;/li&gt;
&lt;li&gt;Build the core feature, nothing else&lt;/li&gt;
&lt;li&gt;Use it yourself for a week&lt;/li&gt;
&lt;li&gt;Then decide if it's worth investing more time&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. No boilerplate, no template, no setup ritual.&lt;/p&gt;

&lt;p&gt;The projects that matter are the ones that exist.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>learning</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why I Built GymDose: A Simple Supplement Tracker for Real Fitness Journeys</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Wed, 03 Dec 2025 21:42:51 +0000</pubDate>
      <link>https://forem.com/baransel/why-i-built-gymdose-a-simple-supplement-tracker-for-real-fitness-journeys-59i5</link>
      <guid>https://forem.com/baransel/why-i-built-gymdose-a-simple-supplement-tracker-for-real-fitness-journeys-59i5</guid>
      <description>&lt;p&gt;Over the last couple of years, fitness has become a huge part of my life. I lost &lt;strong&gt;45 kilograms&lt;/strong&gt; through training, daily cardio, eating better, and staying consistent with my supplements. And even though I was motivated, there was one simple thing I kept messing up:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;I couldn’t remember which supplements I had taken each day.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some mornings I’d double-dose my omega-3 without realizing. Some nights I’d remember I forgot my multivitamin. Some days I’d start creatine loading… and then completely forget the next day.&lt;/p&gt;

&lt;p&gt;It sounds small, but when you’re serious about your fitness, these details matter.&lt;br&gt;&lt;br&gt;
And I hated the feeling of being inconsistent after working so hard.&lt;/p&gt;

&lt;p&gt;That’s how &lt;strong&gt;GymDose&lt;/strong&gt; started — not as an app for the world, but as an app for &lt;em&gt;me&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  From Personal Problem → Personal Tool → Public App
&lt;/h2&gt;

&lt;p&gt;I tried using habit trackers, to-do apps, reminder apps, and “all-in-one” fitness apps.&lt;br&gt;&lt;br&gt;
But everything felt too bloated or unnecessarily complicated.&lt;/p&gt;

&lt;p&gt;I didn’t want badges, charts, motivational quotes, or 40 menu items.&lt;br&gt;&lt;br&gt;
I just wanted something simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the app
&lt;/li&gt;
&lt;li&gt;See my supplements
&lt;/li&gt;
&lt;li&gt;Tap what I took
&lt;/li&gt;
&lt;li&gt;Close it
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;So I built exactly that — a &lt;strong&gt;minimal supplement tracker&lt;/strong&gt; that fits naturally into a fitness routine.&lt;/p&gt;

&lt;p&gt;It started as a private project. Something for my own daily use. But after using it for months, refining the UI, fixing the flow, and realizing it genuinely helped me stay consistent, I decided to release it publicly.&lt;/p&gt;

&lt;p&gt;That’s how &lt;strong&gt;GymDose&lt;/strong&gt; went live on the App Store.&lt;/p&gt;

&lt;p&gt;If you want to try it:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://apps.apple.com/us/app/gymdose-supplement-tracker/id6756020237" rel="noopener noreferrer"&gt;https://apps.apple.com/us/app/gymdose-supplement-tracker/id6756020237&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Designed for People Who Actually Train
&lt;/h2&gt;

&lt;p&gt;GymDose is built from the perspective of someone who loves lifting, supplements, and self-improvement. The design is intentionally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean
&lt;/li&gt;
&lt;li&gt;Dark and minimal
&lt;/li&gt;
&lt;li&gt;Fast to use
&lt;/li&gt;
&lt;li&gt;Zero clutter
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because when you train almost every day, have pre-workout routines, post-workout routines, late-night supplements, and early-morning creatine… the last thing you want is a noisy, over-engineered app.&lt;/p&gt;

&lt;p&gt;The goal was simple:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Make consistency easier than ever.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And because I track my own supplements every single day, every screen was designed with real use in mind.&lt;/p&gt;




&lt;h2&gt;
  
  
  What GymDose Helps You Do
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Log all your supplements
&lt;/h3&gt;

&lt;p&gt;Creatine, omega-3, multivitamin, calcium + D3, protein, collagen — whatever you take regularly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom reminders
&lt;/h3&gt;

&lt;p&gt;Morning, pre-workout, post-workout, night.&lt;br&gt;&lt;br&gt;
Set your own schedule that fits &lt;em&gt;your&lt;/em&gt; routine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean daily overview
&lt;/h3&gt;

&lt;p&gt;See what you already took, what’s left, and what time you usually take each supplement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple progress tracking
&lt;/h3&gt;

&lt;p&gt;Nothing too complicated — just enough to stay aware of your consistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-in measurement units
&lt;/h3&gt;

&lt;p&gt;Grams, pills, scoops, servings.&lt;br&gt;&lt;br&gt;
And you can add your own.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick to use
&lt;/h3&gt;

&lt;p&gt;You can open the app, log your supplements, and close it in 3 seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Built by One Person With a Lot of Care
&lt;/h2&gt;

&lt;p&gt;I built GymDose myself — the design, code, UX, testing, everything.&lt;/p&gt;

&lt;p&gt;And because I’m still deep in my fitness journey, I use the app every day. That’s why every update has a purpose: small improvements that make it easier and smoother to track supplements without thinking about it.&lt;/p&gt;

&lt;p&gt;I’m planning more updates soon, and if you have feedback, I truly read every message.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Supplements Matter in My Journey
&lt;/h2&gt;

&lt;p&gt;When I say supplements helped me, I mean it.&lt;/p&gt;

&lt;p&gt;During my weight loss — from &lt;strong&gt;99 kg down to 54 kg lost total&lt;/strong&gt; — consistency was everything. Supplements aren’t magic, but when you train hard, sleep properly, and eat well, they help you stay healthy, energized, and recover better.&lt;/p&gt;

&lt;p&gt;But consistency is the real game-changer.&lt;/p&gt;

&lt;p&gt;That’s why GymDose exists:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;to remove one tiny barrier from your fitness routine and make staying consistent easier.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Thank You for Checking It Out
&lt;/h2&gt;

&lt;p&gt;If GymDose helps even a few people the way it helped me, it’s worth it.&lt;/p&gt;

&lt;p&gt;Here’s the link again if you want to try it out:&lt;br&gt;
&lt;strong&gt;iOS:&lt;/strong&gt; &lt;a href="https://apps.apple.com/us/app/gymdose-supplement-tracker/id6756020237" rel="noopener noreferrer"&gt;https://apps.apple.com/us/app/gymdose-supplement-tracker/id6756020237&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android:&lt;/strong&gt; &lt;a href="https://play.google.com/store/apps/details?id=com.baransel.dev.gym.supplement.tracker" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.baransel.dev.gym.supplement.tracker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have ideas, suggestions, or anything you want added — tell me.&lt;br&gt;
This app will keep improving.&lt;/p&gt;

&lt;p&gt;Stay consistent. Stay healthy.&lt;br&gt;
And take your supplements. 💪&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>community</category>
      <category>showdev</category>
      <category>coding</category>
    </item>
    <item>
      <title>10 Common JavaScript Pitfalls (and How to Avoid Them)</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Fri, 19 Sep 2025 22:50:53 +0000</pubDate>
      <link>https://forem.com/baransel/10-common-javascript-pitfalls-and-how-to-avoid-them-40i</link>
      <guid>https://forem.com/baransel/10-common-javascript-pitfalls-and-how-to-avoid-them-40i</guid>
      <description>&lt;h1&gt;
  
  
  10 Common JavaScript Pitfalls (and How to Avoid Them)
&lt;/h1&gt;

&lt;p&gt;JavaScript is powerful, flexible, and everywhere — but that flexibility comes with traps. Even experienced devs fall into them. I want to share 10 common pitfalls I’ve seen (or hit myself), and how you can avoid each one. No fluff — just what works.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Why This Matters
&lt;/h2&gt;

&lt;p&gt;If you’ve been coding for a while, you’ve probably hit some strange bugs where the code “looked fine” but behaved completely differently. That’s because JavaScript has quirks: scope issues, async gotchas, type coercion — the list goes on.&lt;/p&gt;

&lt;p&gt;The good news? Once you know these patterns, you can spot and avoid them instantly. Let’s dive in.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 10 Pitfalls to Watch Out For
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Implicit globals&lt;/strong&gt; — forgetting &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;const&lt;/code&gt; makes variables global.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Misusing &lt;code&gt;this&lt;/code&gt;&lt;/strong&gt; — context depends on how the function is called.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Callback hell&lt;/strong&gt; — deeply nested code, hard to maintain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;==&lt;/code&gt; vs &lt;code&gt;===&lt;/code&gt; confusion&lt;/strong&gt; — type coercion surprises.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hoisting quirks&lt;/strong&gt; — &lt;code&gt;var&lt;/code&gt; vs &lt;code&gt;let&lt;/code&gt;/&lt;code&gt;const&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closures inside loops&lt;/strong&gt; — unexpected captured values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async bugs&lt;/strong&gt; — forgetting &lt;code&gt;await&lt;/code&gt;, unhandled promises.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Floating point precision&lt;/strong&gt; — &lt;code&gt;0.1 + 0.2 !== 0.3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inefficient DOM ops&lt;/strong&gt; — reflows, repeated queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overusing dependencies&lt;/strong&gt; — bloated bundles and hidden bugs.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  📱 Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Implicit Globals
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Oops — global variable&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Always declare with &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;const&lt;/code&gt;.&lt;br&gt;
✅ Use linters like ESLint to catch this early.&lt;/p&gt;




&lt;h3&gt;
  
  
  Misusing &lt;code&gt;this&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;greet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// undefined instead of "Alice"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Use arrow functions only when you don’t need &lt;code&gt;this&lt;/code&gt;.&lt;br&gt;
✅ Use &lt;code&gt;.bind()&lt;/code&gt; when necessary.&lt;/p&gt;




&lt;p&gt;…and so on through the rest of the pitfalls.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Avoiding these pitfalls doesn’t mean writing perfect code. It means being aware. Once you recognize these patterns, debugging gets easier, your codebase is cleaner, and teammates will thank you.&lt;/p&gt;

&lt;p&gt;If you enjoyed this, keep an eye out — I’m planning follow-ups on async/await best practices and React pitfalls.&lt;/p&gt;




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

&lt;p&gt;JavaScript isn’t broken — it just has personality. The more you understand it, the more productive (and less frustrated) you’ll be.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How I Lost 35kg and Built a Habit Tracker That Actually Works</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Thu, 08 May 2025 16:57:21 +0000</pubDate>
      <link>https://forem.com/baransel/how-i-lost-35kg-and-built-a-habit-tracker-that-actually-works-146d</link>
      <guid>https://forem.com/baransel/how-i-lost-35kg-and-built-a-habit-tracker-that-actually-works-146d</guid>
      <description>&lt;h1&gt;
  
  
  How I Lost 35kg and Built a Habit Tracker That Actually Works
&lt;/h1&gt;

&lt;p&gt;Six months ago, I was lazy, unfocused, and overwhelmed.&lt;/p&gt;

&lt;p&gt;I’d scroll mindlessly on my phone, work beyond healthy hours, skip workouts, and constantly put off things I knew were good for me. I didn’t need a fancy productivity system — I needed a &lt;em&gt;push&lt;/em&gt;. Something simple. Visual. Relentless.&lt;/p&gt;

&lt;p&gt;That’s when I built &lt;a href="https://play.google.com/store/apps/details?id=com.baransel.dev.dayswithout.habit.tracker" rel="noopener noreferrer"&gt;&lt;strong&gt;Days Without – Habit Tracker&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Why I Built It
&lt;/h2&gt;

&lt;p&gt;I wasn’t aiming to reinvent productivity apps. I built &lt;strong&gt;Days Without&lt;/strong&gt; for myself — because I genuinely needed help. I was tired of breaking promises to myself like “I’ll start tomorrow” or “just 10 more minutes on Instagram.”&lt;/p&gt;

&lt;p&gt;I needed a streak counter. A clear, visual reminder of how long I’ve stuck to something. Something lightweight and shame-free, but still motivating.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;Days Without&lt;/strong&gt;, I started tracking just three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Days without endless scrolling&lt;/li&gt;
&lt;li&gt;Days without working overtime&lt;/li&gt;
&lt;li&gt;Days where I walked or hit the gym&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it. No complex setup, no syncing, no data overload. Just a streak and a purpose.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What Happened Next
&lt;/h2&gt;

&lt;p&gt;In 6 months, I lost &lt;strong&gt;35 kilograms&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I stopped doomscrolling and used that time to move.&lt;/li&gt;
&lt;li&gt;I became aware of how much I was overworking and started setting healthy limits.&lt;/li&gt;
&lt;li&gt;I committed to walking, then lifting, and just kept going.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the coolest part? The app was silently holding me accountable the whole time.&lt;/p&gt;




&lt;h2&gt;
  
  
  📱 About the App
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.baransel.dev.dayswithout.habit.tracker" rel="noopener noreferrer"&gt;&lt;strong&gt;Days Without – Habit Tracker&lt;/strong&gt;&lt;/a&gt; is now live on Google Play. Here’s what it can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track unlimited habits or goals&lt;/li&gt;
&lt;li&gt;Customize each streak with a name and reason&lt;/li&gt;
&lt;li&gt;See your progress in real time: days, hours, and minutes&lt;/li&gt;
&lt;li&gt;Optional motivational quotes&lt;/li&gt;
&lt;li&gt;Minimal design, built for dark mode lovers&lt;/li&gt;
&lt;li&gt;100% privacy-friendly — no accounts or data collection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you want to quit bad habits or build new ones, this app helps you &lt;strong&gt;start&lt;/strong&gt;, and more importantly — &lt;strong&gt;keep going&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Who It’s For
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;Feel stuck in a loop of procrastination&lt;/li&gt;
&lt;li&gt;Want to reduce screen time or social media&lt;/li&gt;
&lt;li&gt;Are trying to build healthy routines&lt;/li&gt;
&lt;li&gt;Need visual motivation to stay consistent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...this app is made for you.&lt;/p&gt;




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

&lt;p&gt;I built &lt;strong&gt;Days Without&lt;/strong&gt; to save myself from my own laziness. Now it’s helping others do the same — and that’s incredibly rewarding.&lt;/p&gt;

&lt;p&gt;If you’re trying to change something in your life, give it a try. It’s simple, clean, and built with real struggle (and real success) behind it.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://play.google.com/store/apps/details?id=com.baransel.dev.dayswithout.habit.tracker" rel="noopener noreferrer"&gt;Download Days Without on Google Play&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if you end up using it — let me know. I’d love to hear your story.&lt;/p&gt;

&lt;p&gt;— Baransel&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>TypeScript: JavaScript's Superhero Cape</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Thu, 24 Oct 2024 21:24:02 +0000</pubDate>
      <link>https://forem.com/baransel/typescript-javascripts-superhero-cape-32eg</link>
      <guid>https://forem.com/baransel/typescript-javascripts-superhero-cape-32eg</guid>
      <description>&lt;h2&gt;
  
  
  Why Add Types to JavaScript?
&lt;/h2&gt;

&lt;p&gt;Picture this: You're happily coding in JavaScript, when suddenly - "Cannot read property 'name' of undefined". Ugh, we've all been there! TypeScript is like having a friend who catches these mistakes before they happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Origin Story
&lt;/h2&gt;

&lt;p&gt;JavaScript is like Peter Parker before the spider bite - great potential, but prone to accidents. TypeScript is the spider bite that gives JavaScript superpowers. It adds a type system that helps catch bugs early and makes your code more reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your First TypeScript Adventure
&lt;/h2&gt;

&lt;p&gt;Let's start with a simple JavaScript function and transform it into TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// JavaScript&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's add some TypeScript magic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TypeScript&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See that &lt;code&gt;: string&lt;/code&gt;? That's TypeScript telling us "this function takes a string and returns a string". Now try this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Error: Argument of type 'number' is not assignable to parameter of type 'string'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript just saved us from a potential bug! 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Types: Your New Superpowers
&lt;/h2&gt;

&lt;p&gt;Let's explore some basic TypeScript types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Basic types&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;heroName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Spider-Man&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isAvenger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;powers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web-slinging&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wall-crawling&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Object type&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;powers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Spider-Man&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;powers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web-slinging&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wall-crawling&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Interfaces: Creating Your Own Types
&lt;/h3&gt;

&lt;p&gt;Interfaces are like blueprints for objects. They're super useful for defining the shape of your data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Hero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;powers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nl"&gt;catchPhrase&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Optional property&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;introduceHero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Hero&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`I am &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, and I'm &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; years old!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catchPhrase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catchPhrase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spiderMan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Hero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Spider-Man&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;powers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web-slinging&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wall-crawling&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;introduceHero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spiderMan&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Type Aliases: Your Custom Types
&lt;/h3&gt;

&lt;p&gt;Sometimes you want to create your own type combinations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PowerLevel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rookie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;intermediate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Hero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;powerLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PowerLevel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;batman&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Hero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Batman&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;powerLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;expert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// TypeScript will ensure this is one of the allowed values&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generics: The Ultimate Flexibility
&lt;/h3&gt;

&lt;p&gt;Generics are like wildcards that make your code more reusable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createHeroTeam&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;members&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;members&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Superhero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;power&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Villain&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;evilPlan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;heroes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createHeroTeam&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Superhero&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Iron Man&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;power&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Technology&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;power&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Lightning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;villains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createHeroTeam&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Villain&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Thanos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;evilPlan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Collect infinity stones&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Example: A Todo App
&lt;/h2&gt;

&lt;p&gt;Let's build a simple todo app with TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoList&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="nf"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dueDate&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;dueDate&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;toggleTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;getTodos&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Todo&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TodoList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;myTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Learn TypeScript with baransel.dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;myTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addTodo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Build awesome apps&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2024-10-24&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  TypeScript with React
&lt;/h2&gt;

&lt;p&gt;TypeScript and React are like peanut butter and jelly. Here's a quick example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;onSuperPower&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HeroCard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onSuperPower&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Age: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onSuperPower&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onSuperPower&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                    Activate Super Power!
                &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tips and Tricks
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start Simple&lt;/strong&gt;: Begin with basic types and gradually add more complex ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the Compiler&lt;/strong&gt;: TypeScript's compiler is your friend - pay attention to its errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't Over-Type&lt;/strong&gt;: Sometimes any is okay (but use it sparingly!).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable Strict Mode&lt;/strong&gt;: Add "strict": true to your tsconfig.json for maximum protection.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common Gotchas and How to Fix Them
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Problem: Object is possibly 'undefined'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Error!&lt;/span&gt;

&lt;span class="c1"&gt;// Solution: Optional chaining&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Problem: Type assertions&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myInput&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Type: HTMLElement | null&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Error!&lt;/span&gt;

&lt;span class="c1"&gt;// Solution: Type assertion or type guard&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;TypeScript might seem like extra work at first, but it's like having a superpower that helps you catch bugs before they happen. Start small, gradually add more types, and before you know it, you'll be wondering how you ever lived without it!&lt;/p&gt;

&lt;p&gt;Remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Types are your friends&lt;/li&gt;
&lt;li&gt;The compiler is your sidekick&lt;/li&gt;
&lt;li&gt;Practice makes perfect&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Git Good: A Beginner's Guide to Version Control Magic</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Tue, 03 Sep 2024 15:11:00 +0000</pubDate>
      <link>https://forem.com/baransel/git-good-a-beginners-guide-to-version-control-magic-21jp</link>
      <guid>https://forem.com/baransel/git-good-a-beginners-guide-to-version-control-magic-21jp</guid>
      <description>&lt;h2&gt;
  
  
  What's All This Git About?
&lt;/h2&gt;

&lt;p&gt;Picture this: You're working on a project, and suddenly you realize you've made a terrible mistake. Wouldn't it be great if you could go back in time? Well, meet Git, your personal time machine for code!&lt;/p&gt;

&lt;p&gt;Git is like a magical notebook that keeps track of every change you make to your project. It's like having infinite "undo" buttons, each one taking you back to a different point in your project's history. Cool, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Git Will Save Your Bacon
&lt;/h2&gt;

&lt;p&gt;1) &lt;strong&gt;Oops-Proof Your Code&lt;/strong&gt;: Made a mistake? No worries! Git lets you rewind to before things went south.&lt;br&gt;
2) &lt;strong&gt;Collaborate Like a Pro&lt;/strong&gt;: Working with others? Git helps you merge your work without stepping on each other's toes.&lt;br&gt;
3) &lt;strong&gt;Experiment Freely&lt;/strong&gt;: Want to try something crazy? Create a branch and go wild without fear of breaking your main project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting Started: Your First Git Steps
&lt;/h2&gt;

&lt;p&gt;Let's dive in and get our hands dirty with some Git basics.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting Up Git
&lt;/h3&gt;

&lt;p&gt;First things first, let's make sure Git is installed and set up:&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="c"&gt;# Check if Git is installed&lt;/span&gt;
git &lt;span class="nt"&gt;--version&lt;/span&gt;

&lt;span class="c"&gt;# Set up your identity&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.name &lt;span class="s2"&gt;"Baransel Arslan"&lt;/span&gt;
git config &lt;span class="nt"&gt;--global&lt;/span&gt; user.email &lt;span class="s2"&gt;"root@baransel.dev"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating Your First Git Repository
&lt;/h3&gt;

&lt;p&gt;Now, let's create a new project and turn it into a Git repository:&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="c"&gt;# Create a new directory&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-awesome-project
&lt;span class="nb"&gt;cd &lt;/span&gt;my-awesome-project

&lt;span class="c"&gt;# Initialize a new Git repository&lt;/span&gt;
git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom! You've just created your first Git repository. It's like you've just opened a new, magical notebook.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Git Workflow: Add, Commit, Push
&lt;/h2&gt;

&lt;p&gt;Here's where the real magic happens. Let's walk through the basic Git workflow:&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Making Changes
&lt;/h3&gt;

&lt;p&gt;Create a new file called &lt;code&gt;hello.txt&lt;/code&gt; and add some text to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Staging Changes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add hello.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is like telling Git, "Hey, keep an eye on this file!"&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Committing Changes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add hello.txt with a friendly greeting"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You've just created your first checkpoint. Git will remember this moment forever!&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Pushing Changes (if you're using a remote repository)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends your changes to a remote repository (like GitHub). It's like backing up your magical notebook to the cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branching Out: Parallel Universes for Your Code
&lt;/h2&gt;

&lt;p&gt;Branches in Git are like parallel universes. You can create a new branch to experiment without affecting your main project.&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="c"&gt;# Create a new branch&lt;/span&gt;
git branch new-feature

&lt;span class="c"&gt;# Switch to the new branch&lt;/span&gt;
git checkout new-feature

&lt;span class="c"&gt;# Or do both in one command&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; another-feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Merging: Bringing It All Together
&lt;/h2&gt;

&lt;p&gt;Once you're happy with your changes in a branch, you can merge it back into your main branch:&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="c"&gt;# Switch back to the main branch&lt;/span&gt;
git checkout main

&lt;span class="c"&gt;# Merge your feature branch&lt;/span&gt;
git merge new-feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Oops Moments: Undoing Things in Git
&lt;/h2&gt;

&lt;p&gt;Made a mistake? No worries! Git has your back:&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="c"&gt;# Undo changes in a file&lt;/span&gt;
git checkout &lt;span class="nt"&gt;--&lt;/span&gt; filename

&lt;span class="c"&gt;# Undo your last commit (but keep the changes)&lt;/span&gt;
git reset HEAD~1

&lt;span class="c"&gt;# Nuclear option: Undo changes and delete commits&lt;/span&gt;
git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; HEAD~1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Git Best Practices: Leveling Up Your Git Game
&lt;/h2&gt;

&lt;p&gt;1) &lt;strong&gt;Commit Early, Commit Often&lt;/strong&gt;: Small, frequent commits are easier to manage than big, infrequent ones.&lt;br&gt;
2) &lt;strong&gt;Write Good Commit Messages&lt;/strong&gt;: Future you will thank present you for clear, descriptive messages.&lt;br&gt;
3) &lt;strong&gt;Use Branches Wisely&lt;/strong&gt;: Keep your main branch stable and experiment in feature branches.&lt;br&gt;
4) &lt;strong&gt;Pull Before You Push&lt;/strong&gt;: Always get the latest changes before pushing your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Tools to Make Your Life Easier
&lt;/h2&gt;

&lt;p&gt;1) &lt;strong&gt;GitHub&lt;/strong&gt;: A popular platform for hosting Git repositories and collaborating with others.&lt;br&gt;
2) &lt;strong&gt;GitKraken&lt;/strong&gt;: A visual Git client that makes branching, merging, and collaborating a breeze.&lt;br&gt;
3) &lt;strong&gt;GitLab&lt;/strong&gt;: An alternative to GitHub with built-in CI/CD pipelines and other cool features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up: You're a Git Wizard Now!
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've taken your first steps into the magical world of Git. It might seem like a lot at first, but with practice, it'll become second nature.&lt;/p&gt;

&lt;p&gt;Remember, Git is here to make your life easier, not harder. It's okay to make mistakes – that's what version control is for!&lt;/p&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Taming the Regex Beast: A Beginner's Guide to Regular Expressions</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Fri, 30 Aug 2024 11:47:15 +0000</pubDate>
      <link>https://forem.com/baransel/taming-the-regex-beast-a-beginners-guide-to-regular-expressions-gh1</link>
      <guid>https://forem.com/baransel/taming-the-regex-beast-a-beginners-guide-to-regular-expressions-gh1</guid>
      <description>&lt;h2&gt;
  
  
  What's This Regex Thing Anyway?
&lt;/h2&gt;

&lt;p&gt;Picture this: You're sifting through a mountain of text, trying to find every email address. Sounds like a job for Ctrl+F, right? Well, not so fast! Enter regular expressions, or "regex" for short. It's like Ctrl+F on steroids, capable of finding patterns instead of just exact matches.&lt;/p&gt;

&lt;p&gt;Regex is like a Swiss Army knife for text processing. Need to validate email addresses? Regex. Want to extract all the URLs from a webpage? Regex. Trying to replace specific patterns in a document? You guessed it – regex to the rescue!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Building Blocks: Your Regex Toolkit
&lt;/h2&gt;

&lt;p&gt;Before we dive into the deep end, let's get familiar with our tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Characters&lt;/strong&gt;: Just your regular, everyday letters and numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metacharacters&lt;/strong&gt;: Special characters with superpowers, like &lt;code&gt;.&lt;/code&gt; (matches any character) or &lt;code&gt;^&lt;/code&gt; (start of a line).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quantifiers&lt;/strong&gt;: These tell us "how many," like &lt;code&gt;*&lt;/code&gt; (zero or more) or &lt;code&gt;+&lt;/code&gt; (one or more).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's like learning a new language, but instead of "Hello, world!" we're saying "Find me a pattern!"&lt;/p&gt;

&lt;h2&gt;
  
  
  Your First Regex: Baby Steps
&lt;/h2&gt;

&lt;p&gt;Let's start simple. Say you want to find all instances of "cat" in a text. Your regex would simply be:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Exciting, right? Okay, maybe not. But what if you want to find "cat" or "Cat"? Try this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Cc]at
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This says "find either 'c' or 'C', followed by 'at'". Now we're cooking!&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Examples: Regex in the Wild
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Validating Email Addresses
&lt;/h3&gt;

&lt;p&gt;Here's a simple regex for catching most email addresses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whoa, that's a mouthful! Let's break it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;^&lt;/code&gt;: Start of the string&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[a-zA-Z0-9._%+-]+&lt;/code&gt;: One or more letters, numbers, or certain symbols&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@&lt;/code&gt;: Literally the @ symbol&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[a-zA-Z0-9.-]+&lt;/code&gt;: One or more letters, numbers, dots, or hyphens&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;\.&lt;/code&gt;: A literal dot (we escape it with a backslash)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[a-zA-Z]{2,}&lt;/code&gt;: Two or more letters&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$&lt;/code&gt;: End of the string&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Extracting URLs from Text
&lt;/h3&gt;

&lt;p&gt;Want to pull out all the URLs from a chunk of text? Try this on for size:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&amp;amp;//=]*)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I know, I know – it looks like a cat walked across your keyboard. But it works!&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding and Replacing Text Patterns
&lt;/h3&gt;

&lt;p&gt;Say you want to replace all instances of "color" with "colour" (hello, British English!). Here's how you might do it in JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The color of the colorful balloon is my favorite color.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;britishText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/color/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;colour&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;britishText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output: "The colour of the colourful balloon is my favorite colour."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Regex in Different Languages: Same Beast, Different Cages
&lt;/h2&gt;

&lt;p&gt;The beauty of regex is that it's pretty universal. Here's how you might use our email validation regex in different languages:&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;emailRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9._%+-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+@&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9.-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z&lt;/span&gt;&lt;span class="se"&gt;]{2,}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example@email.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="n"&gt;email_regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email_regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;example@email.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;re.Match object; span=(0, 17), match='example@email.com'&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PHP
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$email_regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;preg_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$email_regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"example@email.com"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// int(1)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tools of the Trade: Regex Playgrounds
&lt;/h2&gt;

&lt;p&gt;Before you unleash your regex on real data, it's a good idea to test it out. Here are some great online tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://regexr.com/" rel="noopener noreferrer"&gt;RegExr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://regex101.com/" rel="noopener noreferrer"&gt;Regex101&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://regexper.com/" rel="noopener noreferrer"&gt;RegExper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These sites let you test your regex, explain what each part does, and even visualize the pattern. They're like training wheels for your regex bicycle!&lt;/p&gt;

&lt;h2&gt;
  
  
  Watch Out: Common Regex Pitfalls
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Greedy vs. Lazy&lt;/strong&gt;: By default, regex is greedy and will match as much as possible. Use &lt;code&gt;?&lt;/code&gt; after a quantifier to make it lazy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escaping Special Characters&lt;/strong&gt;: Remember to escape special characters with a backslash when you want to match them literally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: Complex regex can be slow on large datasets. Keep it simple when you can!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrapping Up: You've Got the Power!
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've taken your first steps into the powerful world of regular expressions. It might seem daunting at first, but with practice, you'll be slicing and dicing text like a pro.&lt;/p&gt;

&lt;p&gt;Remember, regex is a tool, not a magic wand. Sometimes a simple string method will do the job just fine. But when you need to tame wild text patterns, regex is your best friend.&lt;/p&gt;

&lt;p&gt;So, what text processing challenges are you facing? Drop a comment below and let's see if we can cook up a regex solution together!&lt;/p&gt;

&lt;p&gt;Happy pattern matching, and may your strings always be well-formatted! 🎉&lt;/p&gt;

</description>
      <category>regex</category>
      <category>beginners</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Progressive Web Apps: The Future of Web Development</title>
      <dc:creator>Baransel</dc:creator>
      <pubDate>Thu, 29 Aug 2024 11:55:41 +0000</pubDate>
      <link>https://forem.com/baransel/progressive-web-apps-the-future-of-web-development-3nhg</link>
      <guid>https://forem.com/baransel/progressive-web-apps-the-future-of-web-development-3nhg</guid>
      <description>&lt;h2&gt;
  
  
  What's All This PWA Buzz About?
&lt;/h2&gt;

&lt;p&gt;Picture this: You're on the subway, trying to check a website on your phone, but the signal keeps dropping. Frustrating, right? Enter Progressive Web Apps, the superheroes of the web world. They work offline, load at lightning speed, and even send you notifications. It's like giving your website superpowers!&lt;/p&gt;

&lt;h2&gt;
  
  
  The PWA Origin Story
&lt;/h2&gt;

&lt;p&gt;Back in the day (like, way back in 2015), we had a choice: build a website or build an app. It was like choosing between a bicycle and a car. But then, some clever folks at Google thought, "Why not both?" And thus, the PWA was born!&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Your First PWA: The Adventure Begins
&lt;/h2&gt;

&lt;p&gt;Let's roll up our sleeves and build a simple PWA together. We'll create a "Dad Jokes" app because, well, who doesn't love a good (or bad) dad joke?&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: The Basics - Just a Regular Webpage
&lt;/h3&gt;

&lt;p&gt;First, let's create a basic HTML file. This is our "bicycle" - functional, but not quite super-powered yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Dad Jokes PWA&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Dad Jokes&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"joke"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click the button for a dad joke!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"jokeBtn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Get New Joke&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Add Some Style - Because Even Dad Jokes Need to Look Good
&lt;/h3&gt;

&lt;p&gt;Let's add a touch of CSS to make our app look snazzy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;#joke&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;italic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: The Magic of JavaScript - Fetching Dad Jokes
&lt;/h3&gt;

&lt;p&gt;Now, let's add some JavaScript to fetch jokes from an API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jokeElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;joke&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jokeBtn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jokeBtn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchJoke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://icanhazdadjoke.com/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Accept&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;jokeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;joke&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;jokeElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Oops! Looks like the joke got stuck in dad's old briefcase.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;jokeBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchJoke&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Fetch a joke when the page loads&lt;/span&gt;
&lt;span class="nf"&gt;fetchJoke&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: The PWA Transformation - Adding Superpowers
&lt;/h3&gt;

&lt;p&gt;Now, let's turn our regular website into a PWA. First, we need a manifest file. Create a file named &lt;code&gt;manifest.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dad Jokes PWA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"short_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DadJokes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"display"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standalone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"background_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#ffffff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"theme_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#4285f4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"icons"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"icon.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"sizes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192x192"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image/png"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to add a link to this manifest in your HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;manifest&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;manifest.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: The Secret Sauce - Service Workers
&lt;/h3&gt;

&lt;p&gt;Service workers are like tiny, invisible web butlers. They cache your assets and even work offline. Create a file named &lt;code&gt;service-worker.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CACHE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dad-jokes-cache-v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;urlsToCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/style.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/icon.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;install&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;urlsToCache&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, register this service worker in your &lt;code&gt;app.js&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/service-worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registration&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ServiceWorker registered&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ServiceWorker registration failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Your PWA Superpowers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Offline Mode&lt;/strong&gt;: Turn off your internet and refresh the page. Your app should still work!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install Prompt&lt;/strong&gt;: On supported browsers, you should see an option to install your PWA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lighthouse Audit&lt;/strong&gt;: Use Chrome's Lighthouse tool to check your PWA's superpowers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Future is Progressive
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've just built your first PWA. It's like watching your child take their first steps, isn't it? (Speaking of dad jokes...)&lt;/p&gt;

&lt;p&gt;As we move further into 2024, PWAs are becoming more powerful. They can access device features, work offline, and provide an app-like experience without the hassle of app stores.&lt;/p&gt;

&lt;p&gt;So, the next time someone asks if you can build them a website or an app, you can say, "Why not both?" and introduce them to the wonderful world of PWAs!&lt;/p&gt;

&lt;p&gt;What do you think about PWAs? Have you built one before? Let me know in the comments below, and don't forget to share your favorite dad jokes!&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>javascript</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
