<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[✍️ aiherrera's Blog]]></title><description><![CDATA[My goal is to share my knowledge and insights with fellow developers and foster a collaborative community.]]></description><link>https://blog.aiherrera.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 12:13:30 GMT</lastBuildDate><atom:link href="https://blog.aiherrera.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[HTTPS for local development]]></title><description><![CDATA[💡
UPDATED Feb 8 2026 - Added configuration for NextJS apps


Using HTTPS for local development is no longer optional. Modern browsers require a secure context to enable key features like PWAs, Service Workers, camera access, and WebAuthn. If your lo...]]></description><link>https://blog.aiherrera.com/https-for-local-development</link><guid isPermaLink="true">https://blog.aiherrera.com/https-for-local-development</guid><category><![CDATA[webdev]]></category><category><![CDATA[PWA]]></category><category><![CDATA[vite]]></category><category><![CDATA[https]]></category><category><![CDATA[local development]]></category><category><![CDATA[localhost]]></category><category><![CDATA[offline first]]></category><category><![CDATA[#vite.js]]></category><category><![CDATA[Next.js]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Thu, 29 Jan 2026 19:06:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/89xuP-XmyrA/upload/e08082879dc6e1f4388f416f97c7ebb1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">UPDATED Feb 8 2026 - Added configuration for NextJS apps</div>
</div>

<p>Using HTTPS for local development is no longer optional. Modern browsers require a <strong>secure context</strong> to enable key features like PWAs, Service Workers, camera access, and WebAuthn. If your local dev server still runs on HTTP, you’re likely missing bugs that only appear in production.</p>
<p>This guide shows <strong>how to enable HTTPS on</strong> <a target="_blank" href="http://localhost"><strong>localhost</strong></a> <strong>using Vite and mkcert</strong>, with a setup that works on desktop and real mobile devices.</p>
<hr />
<h2 id="heading-why-https-is-required-for-local-development">Why HTTPS is required for local development</h2>
<p>Browsers restrict powerful APIs to HTTPS to protect users. These restrictions apply even in local development environments.</p>
<p>You need HTTPS on localhost if your app uses:</p>
<ul>
<li><p>Progressive Web Apps (PWA)</p>
</li>
<li><p>Service Workers</p>
</li>
<li><p>Camera or microphone access</p>
</li>
<li><p>WebAuthn / passkeys</p>
</li>
<li><p>Secure cookies and storage APIs</p>
</li>
<li><p>Mobile testing on real devices</p>
</li>
</ul>
<p>While <code>localhost</code> sometimes works without HTTPS, <strong>local IP access does not</strong>. If you test your app on an iPhone or Android device using your machine’s IP, HTTPS is mandatory.</p>
<hr />
<h2 id="heading-best-solution-for-https-on-localhost-mkcert">Best solution for HTTPS on localhost: mkcert</h2>
<p><code>mkcert</code> is the recommended tool for local HTTPS development because it creates <strong>trusted certificates</strong>, not self-signed ones. That means:</p>
<ul>
<li><p>No browser security warnings</p>
</li>
<li><p>Works across browsers</p>
</li>
<li><p>Ideal for Vite, Next.js, and other dev servers</p>
</li>
</ul>
<hr />
<h2 id="heading-step-1-install-mkcert-for-local-https">Step 1: install mkcert for local HTTPS</h2>
<p>On macOS, install mkcert using Homebrew:</p>
<pre><code class="lang-bash">brew install mkcert
mkcert -install
</code></pre>
<p>This creates a local Certificate Authority and adds it to your system trust store.</p>
<hr />
<h2 id="heading-step-2-generate-https-certificates-for-localhost">Step 2: generate HTTPS certificates for localhost</h2>
<p>Generate certificates for localhost and loopback addresses:</p>
<pre><code class="lang-bash">mkcert localhost 127.0.0.1 ::1
</code></pre>
<p>This creates:</p>
<ul>
<li><p><code>localhost.pem</code></p>
</li>
<li><p><code>localhost-key.pem</code></p>
</li>
</ul>
<p>These files will be used by your Vite dev server to enable HTTPS.</p>
<hr />
<h2 id="heading-step-3-enable-https-updated">Step 3: enable HTTPS (UPDATED)</h2>
<ul>
<li>If you are using Vite, edit your <code>vite.config.ts</code> file:</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"fs"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">server</span>: {
    <span class="hljs-attr">host</span>: <span class="hljs-string">"::"</span>,
    <span class="hljs-attr">port</span>: <span class="hljs-number">8080</span>,
    <span class="hljs-attr">https</span>: {
      <span class="hljs-attr">key</span>: fs.readFileSync(<span class="hljs-string">"./localhost-key.pem"</span>),
      <span class="hljs-attr">cert</span>: fs.readFileSync(<span class="hljs-string">"./localhost.pem"</span>),
    },
  },
};
</code></pre>
<ul>
<li>If you are using Nextjs, edit you package.json scripts:</li>
</ul>
<pre><code class="lang-json">{
...
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"next dev --experimental-https --experimental-https-key ./localhost+2-key.pem --experimental-https-cert ./localhost+2.pem"</span>,
    ...
}
</code></pre>
<p>This configuration:</p>
<ul>
<li><p>Enables HTTPS in Vite</p>
</li>
<li><p>Allows IPv4 and IPv6 access</p>
</li>
<li><p>Matches production-like behavior</p>
</li>
</ul>
<p>Restart the dev server after applying the changes.</p>
<hr />
<h2 id="heading-step-4-access-your-https-dev-server-from-mobile-devices">Step 4: access your HTTPS dev server from mobile devices</h2>
<p>To test HTTPS local development on mobile:</p>
<ol>
<li><p>Connect your phone to the same Wi-Fi network</p>
</li>
<li><p>Find your computer’s local IP address</p>
</li>
<li><p>Open the app in your phone browser:</p>
</li>
</ol>
<pre><code class="lang-javascript">https:<span class="hljs-comment">//[your-local-ip]:8080</span>
</code></pre>
<p>This setup works on iOS Safari and Chrome for Android without certificate warnings.</p>
<hr />
<h2 id="heading-why-https-local-development-matters-for-pwas-and-service-workers">Why HTTPS local development matters for PWAs and Service Workers</h2>
<p>PWAs and Service Workers <strong>only work over HTTPS</strong> (except limited <a target="_blank" href="http://localhost">localhost</a> cases). If your PWA behaves differently in production than in development, missing HTTPS is usually the cause.</p>
<p>With this setup, you can:</p>
<ul>
<li><p>Install your PWA locally</p>
</li>
<li><p>Debug Service Worker caching</p>
</li>
<li><p>Test offline behavior</p>
</li>
<li><p>Validate mobile-only features early</p>
</li>
</ul>
<hr />
<h2 id="heading-https-local-development-checklist">HTTPS local development checklist</h2>
<ul>
<li><p>✅ Trusted HTTPS certificates (<code>mkcert</code>)</p>
</li>
<li><p>✅ No browser warnings</p>
</li>
<li><p>✅ Works on real devices</p>
</li>
<li><p>✅ Matches production security rules</p>
</li>
<li><p>✅ Compatible with Vite and modern frameworks</p>
</li>
</ul>
<hr />
<h2 id="heading-conclusion-enable-https-early-in-local-development">Conclusion: enable HTTPS early in local development</h2>
<p>If you’re building modern web applications, <strong>HTTPS on localhost should be your default</strong>, not an afterthought.</p>
<p>Using <code>mkcert</code> with Vite gives you:</p>
<ul>
<li><p>Production parity</p>
</li>
<li><p>Reliable mobile testing</p>
</li>
<li><p>Fewer deployment surprises</p>
</li>
</ul>
<p>Once you switch to HTTPS local development, you won’t want to go back.</p>
]]></content:encoded></item><item><title><![CDATA[Regex beyond the usual: creative uses that actually save you hours]]></title><description><![CDATA[There are two kinds of developers: those who fear regex, and those who use it like a superpower. The funny part? It’s the same tool — the difference is perspective.Most people think of regex as the thing you use to validate emails, phone numbers, or ...]]></description><link>https://blog.aiherrera.com/regex-beyond-the-usual-creative-uses-that-actually-save-you-hours</link><guid isPermaLink="true">https://blog.aiherrera.com/regex-beyond-the-usual-creative-uses-that-actually-save-you-hours</guid><category><![CDATA[Regex]]></category><category><![CDATA[lynsoft]]></category><category><![CDATA[Developer]]></category><category><![CDATA[pattern-matching]]></category><category><![CDATA[code refactoring]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Tue, 04 Nov 2025 17:07:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1762275890971/46b01a06-1050-4c0e-8187-f2c315fa0c14.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are two kinds of developers: those who fear regex, and those who use it like a superpower. The funny part? It’s the same tool — the difference is perspective.<br />Most people think of regex as the thing you use to validate emails, phone numbers, or passwords. But if that’s all you’re using it for, you’re missing 90% of its potential.</p>
<p>Let’s step into the other 90%.<br />These are real-world, <em>unburned</em> uses — the kind of regex tricks that quietly make your workday smoother.</p>
<hr />
<h2 id="heading-1-regex-as-a-debugging-scalpel">1. Regex as a debugging scalpel</h2>
<p>When logs are a mess, regex can turn chaos into insight.<br />Instead of scrolling through thousands of lines, use patterns to isolate only what matters.</p>
<h3 id="heading-example-isolating-failed-api-responses">Example: isolating failed API responses</h3>
<p>Imagine your logs are full of JSON payloads. You can use a regex to extract <em>only the error messages that contain a specific code range</em>:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Imagine a giant log full of JSON-like lines:</span>
cat server.log | grep -Po <span class="hljs-string">'"error":"\K[^"]*(?=.*code":\s*5\d{2})'</span>
</code></pre>
<pre><code class="lang-json">{<span class="hljs-attr">"time"</span>:<span class="hljs-string">"10:22"</span>,<span class="hljs-attr">"error"</span>:<span class="hljs-string">"Database timeout"</span>,<span class="hljs-attr">"code"</span>:<span class="hljs-number">504</span>}
{<span class="hljs-attr">"time"</span>:<span class="hljs-string">"10:23"</span>,<span class="hljs-attr">"error"</span>:<span class="hljs-string">"Missing auth header"</span>,<span class="hljs-attr">"code"</span>:<span class="hljs-number">401</span>}
{<span class="hljs-attr">"time"</span>:<span class="hljs-string">"10:25"</span>,<span class="hljs-attr">"error"</span>:<span class="hljs-string">"Redis unavailable"</span>,<span class="hljs-attr">"code"</span>:<span class="hljs-number">503</span>}
</code></pre>
<p>This isolates all error messages where the status code starts with 5 — perfect for spotting server-side failures, without touching your app logic.</p>
<pre><code class="lang-bash">Database timeout
Redis unavailable
</code></pre>
<hr />
<h2 id="heading-2-regex-as-a-refactor-assistant">2. Regex as a refactor assistant</h2>
<p>Regex can help you refactor your codebase faster than any “find &amp; replace” can dream of.</p>
<h3 id="heading-example-catching-deprecated-function-signatures">Example: catching deprecated function signatures</h3>
<p>Let’s say you renamed <code>fetchUserData()</code> to <code>getUserProfile()</code>, but your teammates forgot to update it everywhere. You can find all lingering usages — even if they’re commented out or spaced oddly:</p>
<pre><code class="lang-javascript">(?&lt;!\/\/\s*)\bfetchUserData\s*\(
</code></pre>
<p>This ignores commented-out lines while still catching real function calls — so your refactors stay clean, not paranoid.</p>
<hr />
<h2 id="heading-3-regex-as-a-data-guardian">3. Regex as a data guardian</h2>
<p>Regex can do compliance work too — like sanitizing logs in milliseconds.<br />Imagine you have sensitive tokens or IDs leaking in production logs 🤯 You can mask them on the fly:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> sanitized = log.replace(
  <span class="hljs-regexp">/(Bearer\s+)[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+/</span>,
  <span class="hljs-string">'$1***.***.***'</span>
);
</code></pre>
<pre><code class="lang-javascript">Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.abc.def
</code></pre>
<p>This keeps your authentication tokens visible enough to debug, but safe enough to share.</p>
<pre><code class="lang-javascript">Authorization: Bearer ***.***.***
</code></pre>
<hr />
<h2 id="heading-4-regex-for-structured-text-mining">4. Regex for structured text mining</h2>
<p>Parsing YAML or INI files? Regex can quickly extract key-value pairs without spinning up a parser.</p>
<h3 id="heading-example-grabbing-config-overrides-from-text-dumps">Example: grabbing config overrides from text dumps</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> text = <span class="hljs-string">`
# Main configuration
APP_ENV=production
DB_HOST=localhost
DB_PORT=5432

# optional overrides
API_KEY = 12345-ABCDE
TIMEOUT=  3000
DEBUG_MODE =false
`</span>;

<span class="hljs-keyword">const</span> regex = <span class="hljs-regexp">/(?&lt;=^|\n)([A-Z_]+)\s*=\s*(.+?)(?=\n|$)/g</span>;
<span class="hljs-keyword">const</span> matches = [...text.matchAll(regex)].map(<span class="hljs-function">(<span class="hljs-params">[_, key, value]</span>) =&gt;</span> ({ key, value }));

<span class="hljs-built_in">console</span>.table(matches);
</code></pre>
<p>Feed it a <code>.env</code> file and it’ll give you all variables and their values — even if there’s inconsistent spacing or comments sprinkled in.  </p>
<p><strong>Output:</strong></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>key</td><td>value</td></tr>
</thead>
<tbody>
<tr>
<td>APP_ENV</td><td>production</td></tr>
<tr>
<td>DB_HOST</td><td><a target="_blank" href="http://localhost">localhost</a></td></tr>
<tr>
<td>DB_PORT</td><td>5432</td></tr>
<tr>
<td>API_KEY</td><td>12345-ABCDE</td></tr>
<tr>
<td>TIMEOUT</td><td>3000</td></tr>
<tr>
<td>DEBUG_MODE</td><td>false</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-5-regex-in-git-hooks-code-quality-gatekeeper">5. Regex in git hooks: code quality gatekeeper</h2>
<p>Add a pre-commit hook that prevents committing <code>console.log()</code> or <code>TODO</code> notes.<br />Because regex can be your quiet code reviewer:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># .git/hooks/pre-commit</span>
<span class="hljs-keyword">if</span> grep -rE <span class="hljs-string">'console\.log|TODO'</span> src/; <span class="hljs-keyword">then</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"🚫 Remove debug statements before committing!"</span>
  <span class="hljs-built_in">exit</span> 1
<span class="hljs-keyword">fi</span>
</code></pre>
<p>Developers start behaving better when regex guards the gate.</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"final cleanup"</span>
🚫 Remove debug statements before committing!
</code></pre>
<hr />
<h2 id="heading-6-regex-for-content-intelligence">6. Regex for content intelligence</h2>
<p>Regex shines when you want to extract context — not just text.</p>
<h3 id="heading-example-extracting-localization-keys-for-translation">Example: extracting localization keys for translation</h3>
<pre><code class="lang-bash">grep -Po <span class="hljs-string">"t\(['\"]([a-z0-9_.-]+)['\"]\)"</span> src/ | grep -Po <span class="hljs-string">"['\"][a-z0-9_.-]+['\"]"</span>
</code></pre>
<pre><code class="lang-javascript">&lt;p&gt;{t(<span class="hljs-string">"dashboard.title"</span>)}&lt;/p&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{t("errors.network")}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{t("profile.logout")}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
</code></pre>
<p>Run this across your repo, and you instantly get a list of every translation key used — great for detecting missing or unused entries in your i18n files.</p>
<pre><code class="lang-javascript"><span class="hljs-string">"dashboard.title"</span>
<span class="hljs-string">"errors.network"</span>
<span class="hljs-string">"profile.logout"</span>
</code></pre>
<hr />
<h2 id="heading-7-regex-and-ai-the-pattern-whisperer">7. Regex and AI: the pattern whisperer</h2>
<p>Regex quietly powers modern AI workflows too.<br />In prompt engineering or data preparation, you often need to clean model output — e.g., extract only bullet lists or numbered answers.</p>
<h3 id="heading-example-filtering-ai-generated-numbered-items">Example: filtering AI-generated numbered items</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> aiResponse = <span class="hljs-string">`
1. Refactor the login flow
2. Add input sanitization
3. Improve caching for heavy queries
`</span>;

<span class="hljs-keyword">const</span> items = aiResponse.match(<span class="hljs-regexp">/(?&lt;=^\d+\.\s)(.*?)(?=\n|$)/gm</span>);
<span class="hljs-built_in">console</span>.log(items);
</code></pre>
<p>You can pipe a model’s raw response through this regex to get just the “content” of the list — no markdown or hallucinated noise.</p>
<pre><code class="lang-javascript">[<span class="hljs-string">"Refactor the login flow"</span>, <span class="hljs-string">"Add input sanitization"</span>, <span class="hljs-string">"Improve caching for heavy queries"</span>]
</code></pre>
<p>Even better: use lookaheads to conditionally extract text <em>before</em> or <em>after</em> specific keywords in LLM output, helping you turn messy text into structured data.</p>
<hr />
<h2 id="heading-8-regex-as-a-ux-ally">8. Regex as a UX ally</h2>
<p>Regex can also enhance user-facing experiences in subtle ways.</p>
<h3 id="heading-example-flexible-user-input-normalization">Example: flexible user input normalization</h3>
<p>Allow users to type phone numbers however they like — regex can normalize them before validation:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> phone = <span class="hljs-string">"55 5123-4567"</span>;
<span class="hljs-keyword">const</span> normalized = phone.replace(<span class="hljs-regexp">/[^\d]/g</span>, <span class="hljs-string">''</span>).replace(<span class="hljs-regexp">/(\d{2})(\d{4})(\d{4})/</span>, <span class="hljs-string">'($1) $2-$3'</span>);
<span class="hljs-built_in">console</span>.log(normalized);
</code></pre>
<p>Now <code>555.123.4567</code> all become the same friendly format.</p>
<hr />
<h2 id="heading-9-regex-in-your-ide-refactoring-like-a-ninja">9. Regex in your IDE: refactoring like a ninja</h2>
<p>Modern editors like VS Code let you apply regex in “Find and Replace.”<br />You can, for instance, transform JSX props en masse:</p>
<h3 id="heading-example-convert-legacy-props-to-new-api-format">Example: convert legacy props to new API format</h3>
<p>Find:</p>
<pre><code class="lang-javascript">label=<span class="hljs-string">"([^"</span>]+)<span class="hljs-string">"\s+value="</span>([^<span class="hljs-string">"]+)"</span>
</code></pre>
<p>Replace:</p>
<pre><code class="lang-text">option={{ label: "$1", value: "$2" }}
</code></pre>
<pre><code class="lang-javascript">&lt;Select label=<span class="hljs-string">"Mexico"</span> value=<span class="hljs-string">"MX"</span> /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Select</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Canada"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"CA"</span> /&gt;</span></span>
</code></pre>
<pre><code class="lang-javascript">&lt;Select option={{ <span class="hljs-attr">label</span>: <span class="hljs-string">"Mexico"</span>, <span class="hljs-attr">value</span>: <span class="hljs-string">"MX"</span> }} /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Select</span> <span class="hljs-attr">option</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">label:</span> "<span class="hljs-attr">Canada</span>", <span class="hljs-attr">value:</span> "<span class="hljs-attr">CA</span>" }} /&gt;</span></span>
</code></pre>
<p>Congratulations — you just migrated 200 dropdowns in one click.</p>
<hr />
<h2 id="heading-the-regex-mindset">The regex mindset</h2>
<p>Regex isn’t about syntax — it’s about pattern recognition.</p>
<p>Once you start seeing patterns everywhere, you’ll use regex for things you never thought of: cleaning datasets, detecting unusual commit formats, shaping AI inputs, or auditing codebases.</p>
<p>Every developer should learn enough regex to stop fearing it and start wielding it.<br />Because once you do, you realize it’s not a tool for matching — it’s a tool for <em>understanding</em>.</p>
]]></content:encoded></item><item><title><![CDATA[Accessibility in Practice: How WCAG 2.2 Makes the Web More Usable for Everyone]]></title><description><![CDATA[Accessibility is no longer a niche concern — it’s the foundation of good design. It ensures that everyone, regardless of their ability, device, or context, can use what we build. For developers and designers, it’s both a moral commitment and, increas...]]></description><link>https://blog.aiherrera.com/accessibility-in-practice-how-wcag-22-makes-the-web-more-usable-for-everyone</link><guid isPermaLink="true">https://blog.aiherrera.com/accessibility-in-practice-how-wcag-22-makes-the-web-more-usable-for-everyone</guid><category><![CDATA[Accessibility]]></category><category><![CDATA[#WCAG]]></category><category><![CDATA[WCAG 2.2]]></category><category><![CDATA[lynsoft]]></category><category><![CDATA[humanity]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Wed, 29 Oct 2025 19:45:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761766978235/40a2b26f-65c2-42e8-b913-175f548f1521.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Accessibility is no longer a niche concern — it’s the foundation of good design. It ensures that everyone, regardless of their ability, device, or context, can use what we build. For developers and designers, it’s both a moral commitment and, increasingly, a legal requirement.</p>
<p>The Web Content Accessibility Guidelines (WCAG), published by the <strong>World Wide Web Consortium (W3C)</strong>, define how to make web content more inclusive. The newest version, <strong>WCAG 2.2</strong> (released October 2023), refines the standards set by 2.1 and introduces new success criteria to address mobile use, cognitive accessibility, and low-vision users.</p>
<p>The good news: if your site already conforms to WCAG 2.1, you’re most of the way there. But the updates in 2.2 highlight critical areas we often overlook — focus visibility, target sizes, authentication, and redundant input.</p>
<h2 id="heading-the-four-pillars-of-accessibility">The four pillars of accessibility</h2>
<p>WCAG 2.2, like its predecessors, is structured around four core principles — <strong>Perceivable, Operable, Understandable, and Robust</strong> (known by the acronym <em>POUR</em>).</p>
<ol>
<li><p><strong>Perceivable:</strong> Content must be presented in ways users can perceive (e.g., alt text, captions, sufficient contrast).</p>
</li>
<li><p><strong>Operable:</strong> Interfaces must work for everyone, including those who rely on keyboards or assistive tech.</p>
</li>
<li><p><strong>Understandable:</strong> Information and navigation should be easy to follow and consistent.</p>
</li>
<li><p><strong>Robust:</strong> Content must work across technologies, from modern browsers to screen readers.</p>
</li>
</ol>
<p>These principles are timeless. WCAG 2.2 builds on them by introducing criteria that reflect how people actually use the web today — particularly on mobile devices and with diverse input methods.</p>
<h2 id="heading-whats-new-in-wcag-22">What’s new in WCAG 2.2</h2>
<p>The <strong>WCAG 2.2 update</strong> adds nine new success criteria. Here are the most impactful for real-world development:</p>
<h3 id="heading-1-focus-not-obscured-2411-minimum-2412-enhanced">1. Focus Not Obscured (2.4.11 – Minimum / 2.4.12 – Enhanced)</h3>
<p>Ever tabbed through a page and lost track of where you were?<br />WCAG 2.2 requires that the <strong>keyboard focus indicator remain visible</strong> at all times — not hidden by sticky headers, pop-ups, or overlays.<br /><strong>Real-life fix:</strong> In a modal dialog, give the focus outline a higher <code>z-index</code> and ensure sufficient contrast. Never rely on color alone to show focus.</p>
<h3 id="heading-2-target-size-258-minimum">2. Target Size (2.5.8 – Minimum)</h3>
<p>Tiny touch targets are a nightmare for users with limited dexterity or tremors.<br />Now, <strong>interactive elements like buttons and links must be at least 24 × 24 CSS pixels</strong>, or provide adequate spacing.<br /><strong>Real-life fix:</strong> If your “Submit” button is 18 × 18 px, increase it to at least 44 × 44 px on mobile. Also ensure clickable icons have padding or invisible hit-areas.</p>
<h3 id="heading-3-dragging-movements-257">3. Dragging Movements (2.5.7)</h3>
<p>Some users can’t perform drag-and-drop actions easily.<br />Provide an <strong>alternative input method</strong>, like a button or keyboard shortcut.<br /><strong>Example:</strong> Allow reordering list items via arrow keys or “Move up/Move down” buttons in addition to drag-and-drop.</p>
<h3 id="heading-4-redundant-entry-337">4. Redundant Entry (3.3.7)</h3>
<p>Users shouldn’t have to re-enter information you already have.<br /><strong>Example:</strong> If your checkout form asks for the shipping address twice, autofill it from the profile or previous step. This helps users with cognitive or memory challenges.</p>
<h3 id="heading-5-accessible-authentication-338">5. Accessible Authentication (3.3.8)</h3>
<p>CAPTCHAs and tricky password puzzles can block users with cognitive, visual, or motor disabilities.<br />Now, authentication processes must <strong>avoid memory or pattern-based tests</strong> without an accessible alternative.<br /><strong>Example:</strong> Replace complex image CAPTCHAs with accessible options (audio CAPTCHA, email link verification, or device push notification).</p>
<h2 id="heading-accessibility-in-everyday-design-and-development">Accessibility in everyday design and development</h2>
<p>Accessibility isn’t just about compliance — it’s about <strong>usability</strong>. Here’s how these guidelines translate into day-to-day decisions:</p>
<h3 id="heading-design-phase">Design phase</h3>
<ul>
<li><p>Ensure color contrast meets <strong>AA (4.5:1)</strong> or <strong>AAA (7:1)</strong> standards.</p>
</li>
<li><p>Use consistent spacing, labels, and button styles to improve comprehension.</p>
</li>
<li><p>Provide visible focus states for all interactive elements — not just the keyboard user.</p>
</li>
</ul>
<h3 id="heading-development-phase">Development phase</h3>
<ul>
<li><p>Use <strong>semantic HTML</strong> (<code>&lt;button&gt;</code>, <code>&lt;label&gt;</code>, <code>&lt;nav&gt;</code>, <code>&lt;main&gt;</code>) before adding ARIA roles.</p>
</li>
<li><p>Test navigation <strong>with a keyboard only</strong> — no mouse, no touchpad.</p>
</li>
<li><p>Avoid “keyboard traps” where users can’t escape a modal or dropdown.</p>
</li>
<li><p>For touch interfaces, test buttons with physical devices and emulate hand tremors (many Android tools support this).</p>
</li>
</ul>
<h3 id="heading-qa-and-testing-phase">QA and testing phase</h3>
<ul>
<li><p>Include accessibility testing in CI/CD.</p>
</li>
<li><p>Use tools like <strong>axe DevTools</strong>, <strong>Lighthouse</strong>, or <strong>WAVE</strong> for automated checks.</p>
</li>
<li><p>Pair automated testing with <strong>manual screen reader tests</strong> (NVDA, VoiceOver).</p>
</li>
</ul>
<hr />
<h2 id="heading-practical-checklist-for-developers">Practical checklist for developers</h2>
<p>Before shipping any feature, ask yourself:</p>
<ol>
<li><p><code>Can every interactive element be reached and operated with a keyboard?</code></p>
</li>
<li><p><code>Does the focus indicator stay visible and clear?</code></p>
</li>
<li><p><code>Are tap targets at least 24×24 px with enough spacing?</code></p>
</li>
<li><p><code>Do forms reuse known information instead of asking again?</code></p>
</li>
<li><p><code>Are login flows accessible without CAPTCHAs or memory tasks?</code></p>
</li>
<li><p><code>Does text have enough contrast, and are color cues not the only indicators?</code></p>
</li>
<li><p><code>Have you tested with a screen reader and real users with assistive tech?</code></p>
</li>
</ol>
<p>If you can answer “yes” to all, you’re likely WCAG 2.2 AA-ready.</p>
<hr />
<h2 id="heading-the-human-side-of-accessibility">The human side of accessibility</h2>
<p>Accessibility is about empathy. Behind every guideline is a real person trying to do something simple — buy groceries, apply for a job, read the news.</p>
<ul>
<li><p>A developer might see “2.5.8 Target Size,” but a user with Parkinson’s sees the difference between frustration and independence.<br />  A designer might see “3.3.7 Redundant Entry,” but a person with dyslexia sees relief from repetitive effort.</p>
</li>
<li><p>When we design inclusively, we make technology that respects people’s time, dignity, and capabilities.</p>
</li>
</ul>
<h2 id="heading-why-accessibility-makes-business-sense">Why accessibility makes business sense</h2>
<p>Accessibility is often framed as a compliance issue, but it’s also <strong>smart business</strong>.</p>
<ul>
<li><p><strong>Broader audience:</strong> More than a billion people worldwide have some form of disability. Accessible design improves UX for all users — for example, captions help people in noisy environments, and high-contrast modes benefit mobile use in sunlight.</p>
</li>
<li><p><strong>Legal protection:</strong> Regions such as the <strong>EU</strong>, <strong>U.S. (ADA + Section 508)</strong>, and <strong>Canada</strong> already require digital accessibility for public and commercial websites.</p>
</li>
<li><p><strong>SEO advantage:</strong> Many accessibility improvements (semantic HTML, descriptive links, alt text) improve search ranking and performance.</p>
</li>
<li><p><strong>Brand trust:</strong> A commitment to inclusion sends a strong ethical signal to users, employees, and partners.</p>
</li>
</ul>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<p>The web was meant to be universal. WCAG 2.2 is our roadmap for keeping it that way.</p>
<p>For developers, accessibility is not a checklist to clear once — it’s an ongoing practice woven into design systems, component libraries, and engineering culture. By baking accessibility into every sprint, we build not only better products but a more equitable internet.</p>
<p>At <a target="_blank" href="https://lynsoft.io">Lynsoft</a>, we believe accessibility is where empathy meets engineering. It’s not about perfection — it’s about intent. Every label we name, every contrast we test, and every flow we refine brings someone closer to inclusion. WCAG 2.2 helps us stay accountable to that mission: making the web usable, human, and open to everyone.</p>
<p>Because accessibility isn’t just good practice — it’s good design, good business, and good humanity.</p>
<hr />
<p><strong>References and further reading</strong></p>
<ul>
<li><p>W3C – <em>Web Content Accessibility Guidelines (WCAG) 2.2</em>: <a target="_blank" href="https://www.w3.org/TR/WCAG22/?utm_source=chatgpt.com">https://www.w3.org/TR/WCAG22/</a></p>
</li>
<li><p>Level Access – <em>WCAG 2.2 AA Summary and Checklist</em>: <a target="_blank" href="https://www.levelaccess.com/blog/wcag-2-2-aa-summary-and-checklist-for-website-owners/?utm_source=chatgpt.com">https://www.levelaccess.com/blog/wcag-2-2-aa-summary-and-checklist-for-website-owners/</a></p>
</li>
<li><p>AccessiBe – <em>Understanding WCAG 2.2</em>: <a target="_blank" href="https://accessibe.com/blog/knowledgebase/wcag-two-point-two?utm_source=chatgpt.com">https://accessibe.com/blog/knowledgebase/wcag-two-point-two</a></p>
</li>
<li><p>W3C WAI – <em>New in WCAG 2.2</em>: <a target="_blank" href="https://www.w3.org/WAI/standards-guidelines/wcag/new-in-22/?utm_source=chatgpt.com">https://www.w3.org/WAI/standards-guidelines/wcag/new-in-22/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Why I trust Hetzner VPS for client projects]]></title><description><![CDATA[Over the years, I’ve deployed projects on all kinds of infrastructure: AWS, GCP, Azure, and plenty of VPS providers. Each has its place. If you’re running a global SaaS at massive scale, AWS makes sense. If you need deep integrations with enterprise ...]]></description><link>https://blog.aiherrera.com/why-i-trust-hetzner-vps-for-client-projects</link><guid isPermaLink="true">https://blog.aiherrera.com/why-i-trust-hetzner-vps-for-client-projects</guid><category><![CDATA[lynsoft]]></category><category><![CDATA[Hetzner]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[vps]]></category><category><![CDATA[hardening]]></category><category><![CDATA[snapshots]]></category><category><![CDATA[backups]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Thu, 11 Sep 2025 05:08:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757567120635/e2fc2a3d-611b-49b5-a7e2-3898ebe98809.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Over the years, I’ve deployed projects on all kinds of infrastructure: AWS, GCP, Azure, and plenty of VPS providers. Each has its place. If you’re running a global SaaS at massive scale, AWS makes sense. If you need deep integrations with enterprise tools, Azure can be the right fit.</p>
<p>But here’s the thing: not every project needs the complexity (or the price tag) of the big clouds. When I’m building fast, when budgets matter, or when I want full control without ten layers of abstraction — that’s when Hetzner shines.</p>
<p>Hetzner isn’t flashy. It doesn’t overwhelm you with 300 services and acronyms. What it does give you is reliable hardware, transparent pricing, and the flexibility to shape the server exactly the way you need it. For a lot of real-world client projects, that’s not just enough — it’s ideal.</p>
<h3 id="heading-picking-the-right-plan-from-an-agency-perspective">Picking the right plan (from an agency perspective)</h3>
<p>Here’s the truth: most of the time, we start projects on Hetzner’s smaller VPS plans. Why? Because speed of iteration matters more than raw specs at the beginning.</p>
<p>At Lynsoft, our rule is:</p>
<ul>
<li><p>Start small, validate fast.</p>
</li>
<li><p>Scale up only when the product or client load demands it.</p>
</li>
<li><p>Always design the system so migration to a bigger plan is painless.</p>
</li>
</ul>
<p>That mindset has saved our clients thousands of dollars and us countless headaches.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><em>Pro tip:</em> Don’t waste budget on day one. Upgrade when your metrics — not your imagination — demand it.</div>
</div>

<h3 id="heading-location-matters-more-than-you-think"><strong>Location matters more than you think</strong></h3>
<p>Hetzner’s regions (Germany, Finland, U.S.) look like a simple dropdown when you create your server. But for us, choosing the right one has a direct impact on user experience.</p>
<p>When Lynsoft deployed an app for a client in Costa Rica, we tested from both the U.S. and German data centers. Latency dropped by nearly half from the U.S. region. That difference translated into snappier dashboards and happier end users.</p>
<p>It’s a small decision during setup that pays off in production.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Here’s a quick way to test which Hetzner server gives you the best response times based on where you are:</div>
</div>

<p><a target="_blank" href="https://hetzner-latency.sliplane.io/"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757569384952/48cd9785-fbbf-46b0-abb7-83594706f565.png" alt="Hetzner Latency Test" class="image--center mx-auto" /></a></p>
<h3 id="heading-security-from-day-one-not-day-ten">Security from day one (not day ten)</h3>
<p>One thing I’ve learned: you don’t secure a server later. Later never comes. The moment a VPS goes live, I run through a quick checklist:</p>
<ul>
<li><p><strong>SSH keys only.</strong> Passwords disabled. Always.</p>
</li>
<li><p><strong>Root login disabled.</strong> No excuses.</p>
</li>
<li><p><strong>UFW firewall enabled.</strong> Allow only what the app needs.</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This isn’t just best practice — it’s what protects your business at 2 a.m. when you’re asleep and some bot farm is knocking on your ports.</div>
</div>

<p>We’ve built a set of tools that automatically harden servers based on the security level you select. The stronger the security, the more system resources it will consume — so the goal is to balance protection with performance. The table below summarizes each (opinionated) level:</p>
<p><img src="https://media.licdn.com/dms/image/v2/D4E12AQESYcWUcQCPSA/article-inline_image-shrink_400_744/B4EZk3PhSjGYAY-/0/1757568439860?e=1760572800&amp;v=beta&amp;t=cmNDnuYRZxjYib0glfbO8aYO9Nmci5Svg-h64ZUi0DM" alt="Security levels from our automated hardening system" /></p>
<pre><code class="lang-markdown">src
 ┣ config
 ┃ ┣ security-levels.conf
 ┃ ┗ system-paths.conf
 ┣ lib
 ┃ ┣ common.sh
 ┃ ┣ config.sh
 ┃ ┣ logging.sh
 ┃ ┣ module-base.sh
 ┃ ┗ validation.sh
 ┣ modules
 ┃ ┣ 01-system-update.sh
 ┃ ┣ 02-ssh-hardening.sh
 ┃ ┣ 03-firewall.sh
 ┃ ┣ 04-fail2ban.sh
 ┃ ┣ 05-kernel-security.sh
 ┃ ┣ 06-auditing.sh
 ┃ ┣ 07-monitoring.sh
 ┃ ┣ 08-security-tools.sh
 ┃ ┣ 09-ubuntu24-features.sh
 ┃ ┣ 10-compliance-scanning.sh
 ┃ ┗ 11-reporting.sh
 ┣ harden.sh
 ┣ install.sh
 ┗ security-validation.sh
</code></pre>
<h3 id="heading-creating-snapshots-like-a-habit">Creating snapshots like a habit</h3>
<p>Every founder has a story about the night they broke production. Mine involves a late-night Nginx config change that locked me out of a server completely. That’s when snapshots stopped being “nice to have” and became non-negotiable.</p>
<p>Now, before I touch critical configs, I make a snapshot in the Hetzner Cloud Console. I label it something obvious like <code>before-docker-update</code> or <code>pre-db-migration</code>. If something goes wrong, I just roll back.</p>
<blockquote>
<p>Key takeaways:</p>
<ol>
<li><p>Take a snapshot in the Hetzner Cloud Console.</p>
</li>
<li><p>Name it clearly (<code>pre-docker-update</code>, <code>before-db-upgrade</code>).</p>
</li>
<li><p>Only then do we touch configs or deploy containers.</p>
</li>
</ol>
</blockquote>
<p>It’s the equivalent of a <strong>“Save Game” button for production.</strong> And when you’re managing multiple projects for clients, it’s not optional — it’s how you sleep at night.</p>
<h3 id="heading-backups-cheap-insurance-for-serious-projects">Backups: cheap insurance for serious projects</h3>
<p>Snapshots are great, but they’re manual. For ongoing client projects, we also enable Hetzner’s automatic backups. It costs a few extra euros per month, but the ROI is huge.</p>
<p>I’ve had a client’s database corrupt after a bad import. Restoring from backup took minutes and avoided what could’ve been a very awkward conversation; it’s saving your <strong>reputation</strong> as a developer and your client’s <strong>trust</strong> in your company.</p>
<p>At Lynsoft, we frame this to clients as part of our <strong>“peace of mind” policy</strong>: we don’t just build software, we safeguard it.</p>
<h3 id="heading-making-the-server-yours">Making the server yours</h3>
<p>Once the basics are in place — updates, security, snapshots, backups — that’s when the fun begins. Some projects get Docker with multiple microservices. Others run on a simple Nginx reverse proxy pointing to a Next.js app. Internal tools sometimes just need a bare Postgres database with monitoring stacked on top.</p>
<p>That’s what I love about Hetzner: the freedom. With AWS for instance, you often feel like you’re being funneled into using their services (RDS for databases, ECS/Fargate for containers, CloudFront for CDN, etc.). With Hetzner, you get the raw building blocks and the control to shape them however you want. You’re in control of what runs on the machine. Want Postgres? Install it yourself. Prefer Docker Swarm, Kubernetes, or Nomad? Spin it up. Nginx, Traefik, Caddy? Your choice.</p>
<p>The important thing isn’t the exact stack — it’s that you own the environment. With Hetzner, we’re not fighting arbitrary limits. We build what the project needs.</p>
<h3 id="heading-the-founders-perspective">The founder’s perspective</h3>
<p>Looking back at all the servers I’ve deployed, one thing stands out: choosing Hetzner isn’t just about saving money. It’s about reliability and control — two things every founder needs when building software that real people rely on.</p>
<p>That doesn’t mean AWS or other cloud giants don’t have their place. If you’ve got deep budgets and need to move at lightning speed with managed services, they can be the right call. But when cost efficiency and flexibility matter, Hetzner is hard to beat.</p>
<p>For me, a well-configured Hetzner VPS is like a solid foundation: invisible to users, but essential for everything built on top.</p>
<p>And if there’s one lesson I’ve learned over the years, it’s this: treat every VPS as if it were going to production tomorrow. Secure it, back it up, and make it yours.</p>
<p>That mindset is what transforms a low-cost server into infrastructure you can trust.</p>
]]></content:encoded></item><item><title><![CDATA[Part 2: Svelte 5 Reactivity and the Role of Runes]]></title><description><![CDATA[Importance of reactivity in web development frameworks
In today’s development world, reactivity has become an essential feature for modern web development frameworks. This is because reactivity allows the user interface to automatically update in res...]]></description><link>https://blog.aiherrera.com/part-2-svelte-5-reactivity-and-the-role-of-runes</link><guid isPermaLink="true">https://blog.aiherrera.com/part-2-svelte-5-reactivity-and-the-role-of-runes</guid><category><![CDATA[Runes]]></category><category><![CDATA[Reactivity]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Mon, 18 Nov 2024 23:59:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731972271708/59c88939-ffb7-4b8e-937d-b91fe81796aa.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-importance-of-reactivity-in-web-development-frameworks">Importance of reactivity in web development frameworks</h3>
<p>In today’s development world, reactivity has become an essential feature for modern web development frameworks. This is because reactivity allows the user interface to automatically update in response to changes in the application state, providing a seamless and dynamic user experience.</p>
<p>With reactivity, developers can create applications that are more interactive and responsive, as the framework efficiently manages the synchronization between the data model and the user interface. This means that when data changes, the UI reflects these changes instantly without requiring manual DOM manipulation.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:798/0*7ICMcW4eCJz4fjeI.jpg" alt="Angular 6|7 RxJS 6 In-Depth Tutorial &amp; Example | by WebTutPro | ITNEXT" /></p>
<p>As a result, it not only enhances the performance of web applications but also simplifies the development process by reducing the amount of code needed to keep the UI in sync with the underlying data. Consequently, frameworks that prioritize reactivity, such as Svelte, are gaining popularity among developers who seek to build efficient and user-friendly applications.</p>
<h3 id="heading-how-popular-frameworks-handle-reactivity">How popular frameworks handle reactivity</h3>
<p>To understand how reactivity is utilized in current web development frameworks, it's important to compare how different frameworks implement this feature.</p>
<p>In frameworks like <strong>React</strong>, reactivity is achieved through a <code>virtual DOM</code> and a component-based architecture. React uses a system of state and props to manage data flow, where changes in state trigger re-renders of components, updating the UI efficiently. This approach allows developers to build complex user interfaces with a clear separation of concerns.</p>
<p><strong>Vue.js</strong> takes a slightly different approach by using a reactive <code>data-binding system</code>. It employs a reactivity system that automatically tracks dependencies and updates the DOM when data changes. Vue's reactivity is more granular, allowing for fine-tuned updates that can improve performance in certain scenarios.</p>
<p><strong>Angular</strong>, on the other hand, uses a <code>two-way data binding mechanism</code>, which synchronizes the model and the view. This means that any changes in the UI are immediately reflected in the model and vice versa. Angular's reactivity is deeply integrated into its framework, providing a robust solution for building large-scale applications.</p>
<p><strong>Svelte</strong> offers a unique take on reactivity by compiling components into highly efficient imperative code that directly manipulates the DOM. This means that Svelte applications do not require a virtual DOM, resulting in faster updates and less overhead. Svelte's reactivity is built into the language itself, making it intuitive and easy to use for developers.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731953916836/94a31485-a17a-41a1-82f1-09d8aab16b4a.png" alt class="image--center mx-auto" /></p>
<p>Each of these frameworks has its own strengths and weaknesses in terms of reactivity, and the choice often depends on the specific needs of the project and the preferences of the development team. By understanding these differences, developers can make informed decisions about which framework best suits their application requirements.</p>
<h3 id="heading-introduction-to-runes-in-svelte-5">Introduction to Runes in Svelte 5</h3>
<p>In the latest version of Svelte, known as Svelte 5, a groundbreaking concept called "Runes" has been introduced. This innovative feature marks a major leap forward in how developers can handle state management and reactivity in their applications. Runes provide a more powerful and flexible way to define and interact with reactive data.</p>
<p>They allow developers to create more complex and dynamic user interfaces with ease. By using Runes, developers can write cleaner and more maintainable code, as they offer a more intuitive approach to managing the flow of data throughout an application.</p>
<h3 id="heading-understanding-runes-through-examples">Understanding Runes Through Examples</h3>
<p>At the time of writing this article, there are currently seven runes integrated into the Svelte 5 framework. These runes are designed to enhance the way developers interact with state and manage reactivity in their applications:</p>
<ul>
<li>$state</li>
</ul>
<pre><code class="lang-typescript">&lt;script&gt;
  <span class="hljs-keyword">let</span> counter = $state(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> increment = <span class="hljs-function">() =&gt;</span> {
    counter++;
  }
&lt;/script&gt;

&lt;button onclick={increment}&gt;Count: {counter}&lt;/button&gt;
</code></pre>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://svelte.dev/playground/d95f478f14a5405198bada3f404caaf2?version=5.2.3">https://svelte.dev/playground/d95f478f14a5405198bada3f404caaf2?version=5.2.3</a></div>
<p> </p>
<ul>
<li>$derived</li>
</ul>
<pre><code class="lang-typescript">&lt;script&gt;
  <span class="hljs-keyword">const</span> price = $state(<span class="hljs-number">100</span>);
  <span class="hljs-keyword">const</span> quantity = $state(<span class="hljs-number">2</span>);
  <span class="hljs-keyword">const</span> total = $derived(price * quantity);
&lt;/script&gt;

&lt;div&gt;
  &lt;p&gt;Price: {price}&lt;/p&gt;
  &lt;p&gt;Quantity: {quantity}&lt;/p&gt;
  &lt;p&gt;Total: {total}&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://svelte.dev/playground/25749993088d4123ad21df6854dbbe49?version=5.2.3">https://svelte.dev/playground/25749993088d4123ad21df6854dbbe49?version=5.2.3</a></div>
<p> </p>
<ul>
<li>$effect</li>
</ul>
<pre><code class="lang-typescript">&lt;script&gt;
  <span class="hljs-comment">// Reactive state for background color</span>
  <span class="hljs-keyword">let</span> backgroundColor = $state(<span class="hljs-string">'#ffffff'</span>);

  <span class="hljs-comment">// Synchronize the state with the document body background</span>
  $effect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">document</span>.body.style.backgroundColor = backgroundColor;
  });
&lt;/script&gt;

&lt;div style=<span class="hljs-string">"padding: 1rem; text-align: center;"</span>&gt;
  &lt;label <span class="hljs-keyword">for</span>=<span class="hljs-string">"color-picker"</span>&gt;Choose background color:&lt;/label&gt;
  &lt;input
    id=<span class="hljs-string">"color-picker"</span>
    <span class="hljs-keyword">type</span>=<span class="hljs-string">"color"</span>
    bind:value={backgroundColor}
    style=<span class="hljs-string">"margin-left: 0.5rem;"</span>
  /&gt;
  &lt;p&gt;The current background color is: {backgroundColor}&lt;/p&gt;
&lt;/div&gt;
</code></pre>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://svelte.dev/playground/de36ebb0c25f4aaa9a6115f619b800d9?version=5.2.3">https://svelte.dev/playground/de36ebb0c25f4aaa9a6115f619b800d9?version=5.2.3</a></div>
<p> </p>
<ul>
<li>$props</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">// MessageComponent.svelte</span>
&lt;script&gt;
  <span class="hljs-keyword">const</span> { message } = $props;
&lt;/script&gt;

&lt;p&gt;{message}&lt;/p&gt;
</code></pre>
<pre><code class="lang-typescript">&lt;MessageComponent message=<span class="hljs-string">"Hello from parent!"</span> /&gt;
</code></pre>
<ul>
<li>$bindable</li>
</ul>
<pre><code class="lang-typescript">&lt;script&gt;
  <span class="hljs-keyword">let</span> { value = $bindable(<span class="hljs-number">0</span>) }: { value: <span class="hljs-built_in">number</span> } = $props();
&lt;/script&gt;

&lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"number"</span> bind:value={value} /&gt;
&lt;p&gt;The value is {value}&lt;/p&gt;
</code></pre>
<pre><code class="lang-typescript">&lt;NumberInput bind:value={myValue} /&gt;
</code></pre>
<ul>
<li>$inspect</li>
</ul>
<pre><code class="lang-typescript">&lt;script&gt;
  <span class="hljs-keyword">let</span> counter = $state(<span class="hljs-number">0</span>);

  $inspect(counter, <span class="hljs-string">'Counter Value'</span>);
&lt;/script&gt;

&lt;button onclick={<span class="hljs-function">() =&gt;</span> counter++)}&gt;
  Increment
&lt;/button&gt;
&lt;p&gt;Counter: {counter}&lt;/p&gt;
</code></pre>
<ul>
<li>$host</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">// ColorPicker.svelte</span>
&lt;svelte:options customElement=<span class="hljs-string">"my-color-picker"</span> /&gt;

&lt;script&gt;
  <span class="hljs-keyword">const</span> colors = [<span class="hljs-string">'red'</span>, <span class="hljs-string">'green'</span>, <span class="hljs-string">'blue'</span>];

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dispatchColor</span>(<span class="hljs-params">color</span>) </span>{
    $host().dispatchEvent(<span class="hljs-keyword">new</span> CustomEvent(<span class="hljs-string">'colorselect'</span>, { detail: color }));
  }
&lt;/script&gt;

&lt;div style=<span class="hljs-string">"display: flex; gap: 10px;"</span>&gt;
  {#each colors <span class="hljs-keyword">as</span> color}
    &lt;button
      style=<span class="hljs-string">"background-color: {color}; width: 50px; height: 50px;"</span>
      onclick={<span class="hljs-function">() =&gt;</span> dispatchColor(color)}
    &gt;&lt;/button&gt;
  {/each}
&lt;/div&gt;
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// App.svelte</span>
&lt;script&gt;
  <span class="hljs-keyword">import</span> <span class="hljs-string">'./ColorPicker.svelte'</span>;

  <span class="hljs-keyword">let</span> selectedColor = <span class="hljs-string">'none'</span>;
&lt;/script&gt;

&lt;my-color-picker
  oncolorselect={<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> selectedColor = event.detail}
/&gt;

&lt;p&gt;Selected color: {selectedColor}&lt;/p&gt;
&lt;div
  style=<span class="hljs-string">"width: 100px; height: 100px; border: 1px solid black; background-color: {selectedColor};"</span>
&gt;&lt;/div&gt;
</code></pre>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://svelte.dev/playground/77700b1365be4504b29ceef2dc09c5cc?version=5.2.3">https://svelte.dev/playground/77700b1365be4504b29ceef2dc09c5cc?version=5.2.3</a></div>
<p> </p>
<blockquote>
<p>What truly sets Svelte 5 apart from other frameworks is how it implements <a target="_blank" href="https://github.com/tc39/proposal-signals?tab=readme-ov-file">Signals</a>. First, they embedded them within the framework. Although this has its own drawbacks, it allows us, for example, to completely remove signals when compiling in server-side rendering mode, as they are unnecessary overhead on the server.</p>
</blockquote>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, Svelte 5 introduces a revolutionary approach to reactivity with the introduction of Runes, offering developers a more intuitive and efficient way to manage state and data flow in their applications.</p>
<ul>
<li><p>By eliminating the need for a virtual DOM and embedding reactivity directly into the language, Svelte 5 provides faster updates and reduced overhead, making it an attractive choice for building modern web applications.</p>
</li>
<li><p>The use of Runes allows for cleaner, more maintainable code and enhances the ability to create complex, dynamic user interfaces.</p>
</li>
<li><p>As Svelte continues to evolve, its innovative features like Runes and Signals position it as a forward-thinking framework with significant potential for future developments in web development.</p>
</li>
</ul>
<p>In <a target="_blank" href="https://blog.aiherrera.com/start-your-journey-with-svelte-5-a-beginners-handbook">Part 1</a> we learn how to quickly set up a Svelte 5 project with their new CLI. Check it out!</p>
<p>In the next part, we will start to create a real-world example project where we’ll add features and show what can be achieved with this great framework. We’ll be working within this simple repo I created for the series: <a target="_blank" href="https://github.com/aiherrera/svelte5-course">Svelte5-course</a>.</p>
<p>So, stay tuned &amp; see ya in next chapter!</p>
]]></content:encoded></item><item><title><![CDATA[Start Your Journey with Svelte 5: A Beginner's Handbook]]></title><description><![CDATA[What Makes Svelte 5 Different?
Svelte 5 is a compiler-based framework that takes a unique approach to web development. Unlike frameworks like React and Vue that use a Virtual DOM to manage reactivity, Svelte compiles your code to vanilla JavaScript d...]]></description><link>https://blog.aiherrera.com/start-your-journey-with-svelte-5-a-beginners-handbook</link><guid isPermaLink="true">https://blog.aiherrera.com/start-your-journey-with-svelte-5-a-beginners-handbook</guid><category><![CDATA[Svelte5]]></category><category><![CDATA[Svelte]]></category><category><![CDATA[Sveltekit]]></category><category><![CDATA[Runes]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Fri, 08 Nov 2024 22:32:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1731098332202/6fcb40cb-1a6c-4bd4-af62-1e9fd42c8582.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-makes-svelte-5-different">What Makes Svelte 5 Different?</h2>
<p><a target="_blank" href="https://svelte.dev/">Svelte 5</a> is a <strong>compiler-based framework</strong> that takes a unique approach to web development. Unlike frameworks like React and Vue that use a Virtual DOM to manage reactivity, Svelte compiles your code to vanilla JavaScript during build time. This approach has several benefits:</p>
<ul>
<li><p><strong>Performance</strong>: No Virtual DOM means less runtime overhead and faster updates.</p>
</li>
<li><p><strong>Smaller Bundle Size</strong>: Svelte only includes the code that your app actually needs, leading to leaner bundle sizes.</p>
</li>
<li><p><strong>Easier Reactivity</strong>: Svelte's reactivity model is simpler, using reactive declarations and <code>$effect</code> runes, which we’ll explore in depth in this series.</p>
</li>
</ul>
<p><strong>Key Features of Svelte 5</strong>:</p>
<ul>
<li><strong>Runes for Fine-Grained Reactivity</strong>: Svelte 5 introduces "runes," a signal-powered reactivity API that provides explicit control over application state. Key runes include <code>$state</code> for declaring reactive variables, <code>$derived</code> for creating reactive values based on other states, and <code>$effect</code> for executing side effects in response to state changes</li>
</ul>
<blockquote>
<p>Due to the reactive nature of Svelte I haven’t found too many use cases where the $effect rune is really needed.</p>
</blockquote>
<ul>
<li><p><strong>Snippets for Reusable Markup</strong>: Replacing the previous slot system, snippets allow developers to define reusable blocks of markup and logic within components. This promotes code organization and reduces redundancy, enhancing component composition.</p>
</li>
<li><p><strong>Enhanced Compiler Performance</strong>: Svelte 5's compiler has been overhauled to generate more optimized JavaScript code, resulting in smaller bundle sizes and faster runtime performance. This improvement leverages Svelte's compiler-first approach to eliminate unnecessary overhead.</p>
</li>
<li><p><strong>Native TypeScript Support</strong>: Svelte 5 offers native TypeScript support, allowing developers to use TypeScript annotations directly within Svelte components. This integration streamlines development workflows and enhances type safety without the need for additional tooling.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">// Just add a lang prop to the script and magic just happens</span>
&lt;script lang=<span class="hljs-string">"ts"</span>&gt;
  <span class="hljs-comment">//...code</span>
&lt;/script&gt;
</code></pre>
<ul>
<li><strong>Simplified Event Handling</strong>: Event handling in Svelte 5 has been refined to reduce boilerplate and increase flexibility. Event handlers are now treated as properties, aligning them with other component properties and simplifying the syntax for attaching event listeners.</li>
</ul>
<pre><code class="lang-typescript">&lt;script lang=<span class="hljs-string">"ts"</span>&gt;
  <span class="hljs-keyword">import</span> WaterPump <span class="hljs-keyword">from</span> <span class="hljs-string">'./WaterPump.svelte'</span>;

  <span class="hljs-keyword">let</span> size = $state(<span class="hljs-number">10</span>);
  <span class="hljs-keyword">let</span> bloomed = $state(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> resetPlant = <span class="hljs-function">() =&gt;</span> {
    size = <span class="hljs-number">10</span>;
    bloomed = <span class="hljs-literal">false</span>;
  }
&lt;/script&gt;

&lt;WaterPump
  water={<span class="hljs-function">(<span class="hljs-params">amount</span>) =&gt;</span> {
    size += amount;
    <span class="hljs-keyword">if</span> (size &gt; <span class="hljs-number">50</span>) bloomed = <span class="hljs-literal">true</span>;
  }}
  dry={<span class="hljs-function">(<span class="hljs-params">amount</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (size &gt; <span class="hljs-number">0</span>) size -= amount;
  }}
/&gt;

{#<span class="hljs-keyword">if</span> bloomed}
  &lt;button onclick={resetPlant}&gt;New Plant&lt;/button&gt;
  &lt;span <span class="hljs-keyword">class</span>=<span class="hljs-string">"flower"</span>&gt;🌸&lt;/span&gt;
{:<span class="hljs-keyword">else</span>}
  &lt;span <span class="hljs-keyword">class</span>=<span class="hljs-string">"plant"</span> style=<span class="hljs-string">"font-size: {0.2 * size}em"</span>&gt;
    🌱
  &lt;/span&gt;
{/<span class="hljs-keyword">if</span>}
</code></pre>
<pre><code class="lang-typescript">&lt;script lang=<span class="hljs-string">"ts"</span>&gt;
  <span class="hljs-keyword">let</span> { water, dry } = $props();
  <span class="hljs-keyword">let</span> amount = $state(<span class="hljs-number">5</span>);
&lt;/script&gt;

&lt;div&gt;
  &lt;button onclick={<span class="hljs-function">() =&gt;</span> water(amount)}&gt;💧 Water&lt;/button&gt;
  &lt;button onclick={<span class="hljs-function">() =&gt;</span> dry(amount)}&gt;☀️ Dry&lt;/button&gt;

  &lt;div&gt;
    &lt;button onclick={<span class="hljs-function">() =&gt;</span> amount--} disabled={amount &lt;= <span class="hljs-number">1</span>}&gt;-&lt;/button&gt;
    &lt;span&gt;Water Amount: {amount}&lt;/span&gt;
    &lt;button onclick={<span class="hljs-function">() =&gt;</span> amount++}&gt;+&lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<ul>
<li><p><strong>Benefits of Vite in SvelteKit</strong></p>
<p>  SvelteKit is built on top of Vite, so we get to tap into its extensive and ever-evolving ecosystem. That means any tool compatible with Vite integrates seamlessly with SvelteKit, giving us a wealth of options to enhance our development experience with minimal setup.</p>
<p>  Here are some practical examples:</p>
<ul>
<li><p><a target="_blank" href="https://vitest.dev/"><strong>Vitest</strong></a> for quick and effective unit and integration testing</p>
</li>
<li><p><a target="_blank" href="https://storybook.js.org/"><strong>Storybook</strong></a> to streamline component-driven development</p>
</li>
<li><p><a target="_blank" href="https://www.npmjs.com/package/@sveltejs/enhanced-img">"@sveltejs/enhanced-img"</a> for static image optimization without extra hassle</p>
</li>
</ul>
</li>
</ul>
<p>    On top of that, SvelteKit leverages Vite's optimized development server and blazing-fast hot module replacement (HMR). This setup keeps our development workflows smooth and responsive, allowing us to see changes instantly and stay focused on building.</p>
<h2 id="heading-setting-up-your-environment">Setting Up Your Environment</h2>
<p>To get started, you need to install <strong>Node.js</strong> (version 20 or higher is recommended) and set up a SvelteKit project.</p>
<h3 id="heading-step-by-step-setup">Step-by-Step Setup</h3>
<p>The Svelte team has shipped a great CLI tool to generate a starter boilerplate project from scratch 🤩</p>
<ol>
<li><p><strong>Install SvelteKit</strong>: Run the following command to create a new SvelteKit project:</p>
<pre><code class="lang-bash"> npx sv create my-app
</code></pre>
</li>
<li><p>Choose any of the three options provided, I always pick the minimal for starting new projects, full-time typescript, prettier, eslint, tailwindcss and many other tools that come out-of-the-box when setting up a new svelte app. Below I left the ones I usually pick:</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1731096796642/b6234d99-bed3-4491-8001-6d98a7ef2de0.png" alt class="image--center mx-auto" /></p>
<p>One amazing thing is that it allows you to start up a local docker container database within the application, fully integrated with drizzle!</p>
<p>Spin up your database with the following command:</p>
<pre><code class="lang-bash">bun run db:start
</code></pre>
<blockquote>
<p>As you may see I’m using bun, lately I’ve been more inclined to it, give it a try!</p>
</blockquote>
<h3 id="heading-project-structure-overview">Project Structure Overview</h3>
<p>SvelteKit uses a file-based routing system, where your file structure directly determines the routes of your application. This is the scaffold of the project within the above picks from the CLI:</p>
<pre><code class="lang-plaintext">TEST/
├── e2e/                       # End-to-end tests (e.g., Playwright)
├── node_modules/              # Dependencies
├── src/
│   ├── lib/                   # Library for utilities, stores, reusable functions/components
│   ├── server/                # Server-specific logic
│   │   ├── db/                # Database-related files (schema, auth)
│   │   │   ├── index.ts
│   │   │   └── schema.ts
│   │   └── auth.ts            # Authentication handling (e.g., Lucia)
│   ├── routes/                # File-based routing for SvelteKit
│   │   ├── demo/              # Example route or feature-specific routes
│   │   └── lucia/
│   │       └── login/         # Authentication routes or specific modules
│   │       ├── +page.svelte
│   │       ├── +page.server.ts
│   │       ├── +layout.svelte
│   │       └── +page.svelte
│   ├── app.css                # Global CSS
│   ├── app.d.ts               # TypeScript declarations for SvelteKit
│   ├── app.html               # Main HTML template for the app
│   ├── demo.spec.ts           # Component or page-specific tests
│   └── hooks.server.ts        # Server hooks for SvelteKit (auth, session handling)
├── static/                    # Static assets (images, icons, etc.)
├── .env                       # Environment variables
├── .env.example               # Example environment variables file
├── .gitignore                 # Git ignore file
├── .npmrc                     # npm configuration file
├── .prettierignore            # Files ignored by Prettier
├── .prettierrc                # Prettier configuration
├── bun.lockb                  # Bun package manager lock file
├── docker-compose.yml         # Docker configuration
├── drizzle.config.ts          # Drizzle ORM configuration
├── eslint.config.js           # ESLint configuration
├── package.json               # Project metadata and dependencies
├── playwright.config.ts       # Playwright configuration for end-to-end testing
├── postcss.config.js          # PostCSS configuration for CSS processing
├── README.md                  # Project documentation
├── svelte.config.js           # SvelteKit configuration
├── tailwind.config.ts         # Tailwind CSS configuration
├── tsconfig.json              # TypeScript configuration
└── vite.config.ts             # Vite configuration
</code></pre>
<h2 id="heading-summary-and-next-steps">Summary and Next Steps</h2>
<p>That’s all folks!</p>
<p>In Part 1, you’ve learned:</p>
<ul>
<li><p>What <strong>differences</strong> <strong>Svelte 5</strong> from other frameworks</p>
</li>
<li><p>Key features that will <strong>streamline your workflow</strong></p>
</li>
<li><p><strong>How to set up a SvelteKit project</strong> and understand its file-based routing structure.</p>
</li>
</ul>
<p>Next, in <strong>Part 2</strong>, we’ll dive into Svelte’s <strong>reactivity model</strong> and explore more on the <strong>runes</strong> concept.</p>
]]></content:encoded></item><item><title><![CDATA[Mastering the Comment Anchors Extension in Visual Studio Code]]></title><description><![CDATA[In the ever-evolving world of software development, keeping your code well-organized and easy to navigate is crucial. One powerful tool to help you achieve this is the Comment Anchors extension in Visual Studio Code (VS Code). This extension allows y...]]></description><link>https://blog.aiherrera.com/mastering-the-comment-anchors-extension-in-visual-studio-code</link><guid isPermaLink="true">https://blog.aiherrera.com/mastering-the-comment-anchors-extension-in-visual-studio-code</guid><category><![CDATA[comment anchors ]]></category><category><![CDATA[comments]]></category><category><![CDATA[vscode extensions]]></category><category><![CDATA[extension]]></category><category><![CDATA[extensions]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[code]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Tue, 11 Jun 2024 20:22:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718135816017/96da79b4-9d4d-45c6-bb10-710e50ea5245.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the ever-evolving world of software development, keeping your code well-organized and easy to navigate is crucial. One powerful tool to help you achieve this is the Comment Anchors extension in Visual Studio Code (VS Code). This extension allows you to create and manage comment anchors within your code, making it easier to navigate and understand complex projects. In this article, we'll explore how to use the Comment Anchors extension to enhance your coding workflow.</p>
<h3 id="heading-what-is-comment-anchors">What is Comment Anchors?</h3>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ExodiusStudios.comment-anchors">Comment Anchors</a> is a VS Code extension that lets you add special markers in your comments, which can then be easily navigated through an integrated panel. These markers help in organizing your code by providing quick access points to important sections or TODOs. This is especially useful in large projects where finding specific pieces of code can be challenging.</p>
<h3 id="heading-installation">Installation</h3>
<p>To install Comment Anchors in VS Code, follow these steps:</p>
<ol>
<li><p><strong>Open VS Code</strong>: Launch your Visual Studio Code editor.</p>
</li>
<li><p><strong>Access Extensions</strong>: Click on the Extensions view icon on the Sidebar or press <code>Ctrl+Shift+X</code>.</p>
</li>
<li><p><strong>Search for Comment Anchors</strong>: Type "Comment Anchors" in the search bar.</p>
</li>
<li><p><strong>Install</strong>: Click on the Install button for the Comment Anchors extension by Exodius Studios.</p>
</li>
</ol>
<p>Once installed, you’re ready to start using Comment Anchors to streamline your coding experience.</p>
<h3 id="heading-basic-usage">Basic Usage</h3>
<h4 id="heading-adding-comment-anchors">Adding Comment Anchors</h4>
<p>To add a comment anchor, you simply add a comment in your code with a specific prefix. The most common prefixes are <code>ANCHOR</code>, <code>TODO</code>, <code>FIXME</code>, <code>NOTE</code>, and <code>SECTION</code>. Here’s how you can add these anchors:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ANCHOR: Imports</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Implement dark mode toggle feature</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-comment">// <span class="hljs-doctag">FIXME:</span> Resolve issue with negative counter values</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleIncrement</span>(<span class="hljs-params"></span>) </span>{
    setCount(<span class="hljs-function"><span class="hljs-params">prevCount</span> =&gt;</span> prevCount + <span class="hljs-number">1</span>);
  }

  <span class="hljs-comment">// STUB: Default decrement handler</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleDecrement</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Implement decrement logic</span>
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {/* NOTE: Button increments the counter */}
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleIncrement}</span>&gt;</span>Increment<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      {/* REVIEW: Ensure counter doesn't display negative values */}
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Counter: {count}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      {/* SECTION: Decrement Button */}
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleDecrement}</span>&gt;</span>Decrement<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Each of these prefixes creates a navigable anchor that you can access later.</p>
<h4 id="heading-viewing-and-navigating-anchors">Viewing and Navigating Anchors</h4>
<p>To view and navigate your comment anchors:</p>
<ol>
<li><p><strong>Open the Comment Anchors Panel</strong>: Go to the Activity Bar and click on the Comment Anchors icon. Alternatively, you can press <code>Ctrl+Shift+P</code> and type "Comment Anchors: Focus Comment Anchors View".</p>
</li>
<li><p><strong>Explore Your Anchors</strong>: The panel will display all the anchors in your project, grouped by file. You can click on any anchor to jump directly to that part of the code.</p>
</li>
</ol>
<h3 id="heading-customizing-comment-anchors">Customizing Comment Anchors</h3>
<p>You can customize the appearance and behavior of your comment anchors through the settings:</p>
<ol>
<li><p><strong>Open Settings</strong>: Press <code>Ctrl+,</code> to open the Settings.</p>
</li>
<li><p><strong>Search for Comment Anchors</strong>: Type "Comment Anchors" in the search bar.</p>
</li>
<li><p><strong>Adjust Settings</strong>: Here, you can modify various settings such as the types of anchors, their color, and their visibility.</p>
</li>
</ol>
<p>For example, you can change the colors for different anchor types to make them stand out more or less, depending on your preference.</p>
<h3 id="heading-advanced-features">Advanced Features</h3>
<h4 id="heading-custom-anchor-types">Custom Anchor Types</h4>
<p>You can define your own anchor types if the default ones don’t meet your needs. To do this:</p>
<ol>
<li><p><strong>Open Settings JSON</strong>: Click on the Open Settings (JSON) icon in the top right corner of the settings page.</p>
</li>
<li><p><strong>Add Custom Types</strong>: Add custom anchor types in the JSON file under the <code>commentAnchors.tags</code> array.</p>
</li>
</ol>
<pre><code class="lang-json"><span class="hljs-string">"commentAnchors.tags"</span>: [
    {
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"HIGHLIGHT"</span>,
        <span class="hljs-attr">"icon"</span>: <span class="hljs-string">"🌟"</span>,
        <span class="hljs-attr">"color"</span>: <span class="hljs-string">"#FFD700"</span>
    },
    {
        <span class="hljs-attr">"name"</span>: <span class="hljs-string">"IMPORTANT"</span>,
        <span class="hljs-attr">"icon"</span>: <span class="hljs-string">"⚠️"</span>,
        <span class="hljs-attr">"color"</span>: <span class="hljs-string">"#FF4500"</span>
    }
]
</code></pre>
<p>These custom types will now be recognized as comment anchors in your code.</p>
<h4 id="heading-filtering-anchors">Filtering Anchors</h4>
<p>You can filter comment anchors by type or by keyword. This is particularly useful when you want to focus on specific types of comments, like TODOs or FIXMEs. Use the search box in the Comment Anchors panel to filter anchors.</p>
<h4 id="heading-synchronizing-anchors">Synchronizing Anchors</h4>
<p>The extension also allows synchronization of comment anchors across multiple files. This means you can have a unified view of all important comments across your entire project, making it easier to keep track of tasks and important notes.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>The Comment Anchors extension is a powerful tool that can significantly improve your productivity in Visual Studio Code. By allowing you to mark and navigate important comments throughout your codebase, it helps keep your projects organized and manageable. Whether you are working on a large project with multiple contributors or a solo venture, Comment Anchors provides a seamless way to keep track of your code.</p>
<p>Install Comment Anchors today and start experiencing a more efficient way to manage and navigate your code!</p>
<hr />
<p>This guide should give you a solid foundation for using the <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ExodiusStudios.comment-anchors">Comment Anchors</a> extension in VS Code. Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Learn the basic concepts of Next.js 14]]></title><description><![CDATA[Introduction
Next.js has long been a favored framework for developers seeking to build fast and efficient web applications. With the release of Next.js 14, there's much to be excited about. The evolution of web development tools and frameworks has al...]]></description><link>https://blog.aiherrera.com/learn-the-basic-concepts-of-nextjs-14</link><guid isPermaLink="true">https://blog.aiherrera.com/learn-the-basic-concepts-of-nextjs-14</guid><category><![CDATA[Next.js]]></category><category><![CDATA[server actions]]></category><category><![CDATA[Mutations]]></category><category><![CDATA[caching]]></category><category><![CDATA[optimization]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[Accessibility]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Mon, 03 Jun 2024 06:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718321175006/aef01f88-95d7-4a14-8849-1e6faca41c7b.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p><a target="_blank" href="https://nextjs.org/">Next.js</a> has long been a favored framework for developers seeking to build fast and efficient web applications. With the release of Next.js 14, there's much to be excited about. The evolution of web development tools and frameworks has always been a driving force in the tech industry, guiding how developers create, deploy, and maintain applications.</p>
<p>This article will explore the introduction of new features such as enhanced forms, layouts, caching, authentication methods, accessibility improvements, and middleware enhancements. These advancements are set to redefine development practices by offering more efficient solutions to common challenges, thereby enabling developers to craft more powerful and responsive applications with ease.</p>
<h2 id="heading-new-features-and-enhancements">New Features and Enhancements</h2>
<p>Next.js 14 is packed with features designed to enhance the development experience, improve performance, and offer more flexibility. Here are some of the most notable updates:</p>
<h3 id="heading-simplifying-data-mutations">Simplifying Data Mutations</h3>
<p>Gone are the days of manually creating API Routes. With Next.js 14, developers can define functions that securely run on the server, directly from React components. This approach not only streamlines server-centric data mutations but also integrates with web fundamentals like forms and the FormData Web API. Developers can use Server Actions through a form for progressive enhancement or call them directly as functions, ensuring type-safety with TypeScript and efficient network roundtrips.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create</span>(<span class="hljs-params">formData</span>) </span>{
    <span class="hljs-string">'use server'</span>;
    <span class="hljs-keyword">const</span> id = <span class="hljs-keyword">await</span> createItem(formData);
  }
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{create}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-mutations-updating-data-on-the-server">Mutations: Updating Data on the Server</h3>
<p>Mutations in Next.js 14 are actions that change the state of data on the server. They are essential for operations like creating, updating, or deleting records in a database. Mutations ensure that data integrity is maintained while allowing for responsive user interfaces.</p>
<p><strong>Key Concepts:</strong></p>
<ol>
<li><p><strong>Data Integrity</strong>: Mutations help maintain consistency in your data by ensuring that changes are applied in a controlled manner.</p>
</li>
<li><p><strong>Optimistic Updates</strong>: Next.js supports optimistic updates, where the UI is updated immediately, and the server change is applied in the background. This provides a smoother user experience.</p>
</li>
</ol>
<p><strong>Example: Server Mutation for Database Update</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { mutateServer } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateUserData</span>(<span class="hljs-params">userId, newData</span>) </span>{
    <span class="hljs-string">'use server'</span>;
    <span class="hljs-comment">// Update user data in the database</span>
    <span class="hljs-keyword">const</span> updatedUser = <span class="hljs-keyword">await</span> database.users.update(userId, newData);
    <span class="hljs-keyword">return</span> updatedUser;
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {/* UI components */}
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> updateUserData(1, { name: 'John Doe' })}&gt;Update User<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>This example demonstrates a server mutation that updates user data in a database, ensuring that changes are handled securely and efficiently on the server.</p>
<h3 id="heading-integrating-server-actions-with-the-app-router">Integrating Server Actions with the App Router</h3>
<p>The App Router in Next.js 14 provides a streamlined approach to integrating server actions and mutations within your application. This allows for a clear separation of client-side and server-side logic, facilitating better code organization and maintainability.</p>
<p><strong>Steps to Integrate Server Actions:</strong></p>
<ol>
<li><p><strong>Define Server Actions</strong>: Create server action functions within your component files, marked with <code>'use server'</code> to indicate server-side execution.</p>
</li>
<li><p><strong>Call Server Actions</strong>: Use these functions within your components to handle tasks like data fetching or form submissions.</p>
</li>
<li><p><strong>Handle Responses</strong>: Ensure that responses from server actions are properly managed, updating the UI as necessary.</p>
</li>
</ol>
<p><strong>Example: Integrating Server Action in App Router</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { serverAction } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Profile</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">saveProfile</span>(<span class="hljs-params">data</span>) </span>{
    <span class="hljs-string">'use server'</span>;
    <span class="hljs-comment">// Save profile data</span>
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> profileService.save(data);
    <span class="hljs-keyword">return</span> result;
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {/* UI components */}
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{saveProfile}</span>&gt;</span>
        {/* Form fields */}
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Save Profile<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In this setup, the <code>saveProfile</code> function is a server action integrated within the App Router, providing a cohesive and efficient way to handle profile updates.</p>
<blockquote>
<h4 id="heading-practical-tips-and-best-practices">Practical Tips and Best Practices</h4>
<ul>
<li><p><strong>Use the App Router</strong> for a clear distinction between server and client components, ensuring better organization and maintainability.</p>
</li>
<li><p><strong>Leverage ISR</strong> for pages with content that changes periodically, allowing for automatic updates without the need for manual intervention.</p>
</li>
<li><p><strong>Optimize Cache Settings</strong> by setting appropriate cache headers and revalidation intervals to balance performance and data freshness.</p>
</li>
<li><p><strong>Monitor Data Usage</strong> to avoid excessive data fetching, which can lead to performance bottlenecks. Use tools like Next.js analytics to track data fetching metrics.</p>
</li>
</ul>
</blockquote>
<h3 id="heading-integration-with-caching-and-revalidation">Integration with Caching and Revalidation</h3>
<h4 id="heading-data-fetching-with-the-app-router">Data Fetching with the App Router</h4>
<p>The App Router in Next.js 14 simplifies data fetching by providing a structured way to manage server-side and client-side data needs. The approach emphasizes component-based data fetching, allowing for better separation of concerns and easier maintenance.</p>
<p><strong>Key Concepts:</strong></p>
<ol>
<li><p><strong>Server Components</strong>: These components handle server-side rendering and can fetch data directly from the server. They do not include client-side JavaScript and are ideal for scenarios where SEO and initial load performance are critical.</p>
</li>
<li><p><strong>Client Components</strong>: These components fetch data on the client side and are used for interactive features. They allow for dynamic data fetching using hooks like <code>useEffect</code> and <code>useState</code>.</p>
</li>
</ol>
<p><strong>Example: Fetching Data with Server Components</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { fetchPosts } <span class="hljs-keyword">from</span> <span class="hljs-string">'../lib/api'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> fetchPosts();
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {posts.map(post =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>&gt;</span>{post.title}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In this example, data is fetched on the server and rendered directly, reducing the need for additional client-side data fetching.</p>
<h4 id="heading-caching-strategies">Caching Strategies</h4>
<p>Caching is essential for improving performance and reducing server load by storing responses and reusing them for subsequent requests. Next.js 14 offers several caching mechanisms that can be integrated seamlessly with the App Router.</p>
<p><strong>Types of Caching:</strong></p>
<ol>
<li><p><strong>Static Generation</strong>: Pages are generated at build time and served as static files. This approach is suitable for content that does not change frequently.</p>
</li>
<li><p><strong>Incremental Static Regeneration (ISR)</strong>: Allows you to update static pages incrementally after the initial build. This ensures that the pages remain up-to-date without rebuilding the entire site.</p>
</li>
</ol>
<p><strong>Implementing ISR Example:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> fetchPosts();
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: { posts },
    <span class="hljs-attr">revalidate</span>: <span class="hljs-number">60</span>, <span class="hljs-comment">// Revalidate every 60 seconds</span>
  };
}
</code></pre>
<p>In this setup, the <code>revalidate</code> parameter ensures that the data is refreshed periodically, providing a balance between performance and data freshness.</p>
<h4 id="heading-revalidation-techniques">Revalidation Techniques</h4>
<p>Revalidation is the process of updating stale data with fresh data from the server. Next.js 14 makes this process straightforward, allowing developers to set revalidation intervals and manage data consistency effectively.</p>
<p><strong>Revalidation Strategies:</strong></p>
<ol>
<li><p><strong>On-Demand Revalidation</strong>: Trigger revalidation based on specific events or user actions.</p>
</li>
<li><p><strong>Background Revalidation</strong>: Automatically update data in the background while serving stale content until the new data is ready.</p>
</li>
</ol>
<p><strong>Example: On-Demand Revalidation</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { revalidatePath } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/cache'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">await</span> revalidatePath(<span class="hljs-string">'/path-to-revalidate'</span>);
  res.json({ <span class="hljs-attr">revalidated</span>: <span class="hljs-literal">true</span> });
}
</code></pre>
<p>This example demonstrates how to trigger revalidation for a specific path, ensuring that the most current data is served to users.</p>
<blockquote>
<h4 id="heading-practical-tips-and-best-practices-1">Practical Tips and Best Practices</h4>
<ul>
<li><p><strong>Use the App Router</strong> for a clear distinction between server and client components, ensuring better organization and maintainability.</p>
</li>
<li><p><strong>Leverage ISR</strong> for pages with content that changes periodically, allowing for automatic updates without the need for manual intervention.</p>
</li>
<li><p><strong>Optimize Cache Settings</strong> by setting appropriate cache headers and revalidation intervals to balance performance and data freshness.</p>
</li>
<li><p><strong>Monitor Data Usage</strong> to avoid excessive data fetching, which can lead to performance bottlenecks. Use tools like Next.js analytics to track data fetching metrics.</p>
</li>
</ul>
</blockquote>
<h3 id="heading-enhanced-middleware-capabilities"><strong>Enhanced Middleware Capabilities</strong></h3>
<h4 id="heading-understanding-middleware">Understanding Middleware</h4>
<p>Middleware in Next.js 14 operates at the edge of your application, allowing you to run code before a request is completed. This can be used for a variety of tasks such as modifying response headers, handling authentication, and implementing redirects.</p>
<p><strong>Key Concepts:</strong></p>
<ol>
<li><p><strong>Request Interception</strong>: Middleware can intercept requests and modify them before they reach the application’s main logic.</p>
</li>
<li><p><strong>Edge Functions</strong>: Middleware runs on the edge, closer to the user, which reduces latency and improves performance.</p>
</li>
<li><p><strong>Global Scope</strong>: Unlike API routes, middleware can be applied globally across your application, providing a centralized approach to request handling.</p>
</li>
</ol>
<p><strong>Example: Middleware for Authentication</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { NextResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/server'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">middleware</span>(<span class="hljs-params">request</span>) </span>{
  <span class="hljs-keyword">const</span> token = request.cookies.get(<span class="hljs-string">'auth-token'</span>);

  <span class="hljs-keyword">if</span> (!token) {
    <span class="hljs-keyword">return</span> NextResponse.redirect(<span class="hljs-keyword">new</span> URL(<span class="hljs-string">'/login'</span>, request.url));
  }

  <span class="hljs-keyword">return</span> NextResponse.next();
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> config = {
  <span class="hljs-attr">matcher</span>: [<span class="hljs-string">'/dashboard/:path*'</span>],
};
</code></pre>
<p>This middleware checks for an authentication token and redirects unauthenticated users to the login page, ensuring that only authorized users can access protected routes.</p>
<h4 id="heading-middleware-use-cases">Middleware Use Cases</h4>
<p>Middleware can be used for a wide range of scenarios, from simple request handling to complex logic execution. Here are some common use cases:</p>
<ol>
<li><p><strong>Authentication and Authorization</strong>: Verify user credentials and permissions before granting access to protected resources.</p>
</li>
<li><p><strong>Localization</strong>: Redirect users to different versions of the site based on their location or language preferences.</p>
</li>
<li><p><strong>Analytics and Logging</strong>: Collect and log request data for analytics and monitoring purposes.</p>
</li>
<li><p><strong>Content Personalization</strong>: Customize content delivery based on user preferences or behaviors.</p>
</li>
</ol>
<h3 id="heading-faster-code-updates-with-fast-refresh">Faster Code Updates with Fast Refresh</h3>
<p>Fast Refresh in Next.js 14 has revolutionized the way we handle code updates which has became up to <strong>96.3% faster</strong>. This enhancement allows developers to see changes almost instantaneously, fostering a more dynamic and efficient coding environment. The integration of Fast Refresh with Turbopack means that changes in React components are reflected immediately without the need for a full page reload, making the development cycle quicker and more responsive. Additionally, error handling has been improved, allowing developers to catch and correct mistakes swiftly without disrupting the overall flow.</p>
<p>By streamlining these critical aspects of the development process, Next.js 14 not only enhances productivity but also significantly elevates the user experience for developers.</p>
<h3 id="heading-improved-image-optimization"><strong>Improved Image Optimization</strong></h3>
<p>Image optimization has always been a strong suit of Next.js, and version 14 takes it a step further. The new image component in Next.js 14 comes with automatic lazy loading and format selection, ensuring that images are delivered in the most optimal format and size. This not only enhances p<a target="_blank" href="https://www.linkedin.com/pulse/nextjs-fast-refresh-see-changes-instantly-amitha-h-al8bf">age</a> load speeds but also improves overall user experience.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">'next/image'</span>
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">'next/link'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Logo</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Logo"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Image</span> <span class="hljs-attr">priority</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/logomark.png"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">{60}</span> <span class="hljs-attr">height</span>=<span class="hljs-string">{60}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Logomark"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span></span>
  )
}
</code></pre>
<h3 id="heading-better-typescript-support"><strong>Better TypeScript Support</strong></h3>
<p>Next.js 14 brings better integration with TypeScript, making it easier for developers to write and maintain type-safe code. With enhanced TypeScript support, developers can catch errors early in the development process, leading to more robust and reliable applications.</p>
<blockquote>
<p>Pro Tip: The new App Router allows end-to-end type safety if you use a content provider or a database that supports Typescript, ex. an ORM.</p>
</blockquote>
<h3 id="heading-improving-accessibility">Improving Accessibility</h3>
<p>Accessibility is a crucial aspect of web development, ensuring that all users, including those with disabilities, can effectively interact with your website or application. Next.js 14 emphasizes the importance of building inclusive web experiences by providing tools and best practices for enhancing accessibility. This chapter explores how to integrate accessibility features in your Next.js projects, focusing on strategies, tools, and practical implementations.</p>
<h4 id="heading-the-importance-of-accessibility">The Importance of Accessibility</h4>
<p>Web accessibility ensures that websites and applications are usable by everyone, including people with visual, auditory, motor, and cognitive impairments. Accessibility not only promotes inclusivity but also improves the overall user experience and can enhance SEO and legal compliance.</p>
<p><strong>Key Principles of Accessibility:</strong></p>
<ol>
<li><p><strong>Perceivable</strong>: Information and UI components must be presentable in ways that users can perceive, regardless of their abilities.</p>
</li>
<li><p><strong>Operable</strong>: Users must be able to interact with and navigate the interface easily.</p>
</li>
<li><p><strong>Understandable</strong>: The content and operation of the interface should be clear and intuitive.</p>
</li>
<li><p><strong>Robust</strong>: Content must be robust enough to be interpreted reliably by a wide variety of user agents, including assistive technologies.</p>
</li>
</ol>
<h4 id="heading-accessibility-features-in-nextjs-14">Accessibility Features in Next.js 14</h4>
<p>Next.js 14 offers several built-in features and recommendations to help developers create accessible applications. By following these guidelines, you can ensure that your applications are inclusive and provide a seamless user experience for everyone.</p>
<p><strong>Key Features:</strong></p>
<ol>
<li><p><strong>Semantic HTML</strong>: Use HTML elements that convey meaning and structure, aiding assistive technologies in interpreting content.</p>
</li>
<li><p><strong>ARIA Roles and Properties</strong>: Utilize Accessible Rich Internet Applications (ARIA) roles and properties to enhance the semantic meaning of UI components.</p>
</li>
<li><p><strong>Focus Management</strong>: Ensure that focus is managed appropriately to help users navigate your application using keyboards or other assistive devices.</p>
</li>
<li><p><strong>Responsive Design</strong>: Design for a variety of devices and screen sizes, ensuring that content is accessible on mobile and desktop platforms.</p>
</li>
</ol>
<p><strong>Example: Using Semantic HTML</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">About</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>About Us<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Our Mission<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>We strive to make the web accessible to everyone.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>In this example, semantic HTML tags like <code>&lt;main&gt;</code>, <code>&lt;h1&gt;</code>, and <code>&lt;section&gt;</code> provide a clear structure, aiding both users and assistive technologies in understanding the content.</p>
<h4 id="heading-tools-and-techniques-for-accessibility">Tools and Techniques for Accessibility</h4>
<p>Next.js 14 integrates with various tools and techniques to help you test and improve the accessibility of your applications. These tools can identify issues and provide recommendations for making your site more inclusive.</p>
<p><strong>Key Tools:</strong></p>
<ol>
<li><p><strong>Lighthouse</strong>: A tool integrated into Chrome DevTools that audits your site for accessibility, performance, and SEO.</p>
</li>
<li><p><strong>Axe</strong>: A powerful accessibility testing tool that can be used in browser extensions or as part of your CI/CD pipeline.</p>
</li>
<li><p><strong>Screen Readers</strong>: Tools like NVDA and VoiceOver help simulate the experience of visually impaired users, allowing you to test the accessibility of your site.</p>
</li>
</ol>
<p><strong>Example: Running an Accessibility Audit with Lighthouse</strong></p>
<ol>
<li><p>Open Chrome DevTools.</p>
</li>
<li><p>Navigate to the "Lighthouse" tab.</p>
</li>
<li><p>Select the "Accessibility" checkbox.</p>
</li>
<li><p>Click "Generate report" to see a detailed audit of your site's accessibility.</p>
</li>
</ol>
<p>The Lighthouse report provides insights and actionable recommendations to enhance your site’s accessibility, such as fixing contrast issues or adding alternative text to images.</p>
<h4 id="heading-practical-implementation-of-accessibility">Practical Implementation of Accessibility</h4>
<p>Incorporating accessibility into your Next.js 14 projects involves following best practices and utilizing the right tools to ensure your site meets accessibility standards.</p>
<p><strong>Best Practices:</strong></p>
<ol>
<li><p><strong>Use Alt Text for Images</strong>: Provide descriptive alternative text for images to aid users who rely on screen readers.</p>
</li>
<li><p><strong>Ensure Keyboard Navigation</strong>: Make sure all interactive elements are accessible via keyboard, and avoid using tabindex values greater than zero.</p>
</li>
<li><p><strong>Provide ARIA Landmarks</strong>: Use ARIA roles like <code>role="banner"</code> or <code>role="main"</code> to help users navigate your site more effectively.</p>
</li>
<li><p><strong>Test with Assistive Technologies</strong>: Regularly test your application using screen readers and other assistive technologies to identify and address accessibility issues.</p>
</li>
</ol>
<p><strong>Example: Enhancing a Form for Accessibility</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ContactForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"contact-form-heading"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"contact-form-heading"</span>&gt;</span>Contact Us<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"name"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">aria-required</span>=<span class="hljs-string">"true"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">aria-required</span>=<span class="hljs-string">"true"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p>This form includes labels linked to their corresponding inputs, ARIA labels, and a clear form structure, making it easier for users with assistive technologies to interact with it.</p>
<h4 id="heading-accessibility-testing-and-cicd-integration">Accessibility Testing and CI/CD Integration</h4>
<p>Incorporating accessibility testing into your continuous integration and delivery (CI/CD) process ensures that your application remains accessible throughout development.</p>
<p><strong>Steps to Integrate Accessibility Testing:</strong></p>
<ol>
<li><p><strong>Choose a Testing Tool</strong>: Select a tool like Axe or Lighthouse CI that fits your development workflow.</p>
</li>
<li><p><strong>Set Up Automated Tests</strong>: Configure your CI/CD pipeline to run accessibility tests on every build.</p>
</li>
<li><p><strong>Monitor and Address Issues</strong>: Regularly review test results and address any accessibility issues that arise.</p>
</li>
</ol>
<p><strong>Example: Integrating Axe in CI/CD</strong></p>
<pre><code class="lang-javascript"># Install Axe CLI
npm install -g axe-cli

# Run Axe on your site
axe https:<span class="hljs-comment">//example.com --save --format=json --output=axe-report.json</span>
</code></pre>
<p>By integrating Axe into your CI/CD pipeline, you can automatically check for accessibility issues and generate reports, ensuring that accessibility remains a priority throughout development.</p>
<h3 id="heading-improvements-from-previous-versions">Improvements from Previous Versions</h3>
<p>To fully appreciate the advancements in Next.js 14, let's compare it with some of the key features from previous versions:</p>
<ul>
<li><p><strong>Next.js 10</strong> focused on image optimization and internationalization. Next.js 14 takes these features further with enhanced image component capabilities and improved support for global applications.</p>
</li>
<li><p><strong>Next.js 12</strong> introduced the innovative middleware API, which laid the groundwork for the advanced capabilities we see in Next.js 14. However, the latest version offers more flexibility and control, making it a significant upgrade.</p>
</li>
<li><p><strong>Next.js 13</strong> brought improvements in server-side rendering and static site generation. While these features made development more efficient, Next.js 14 builds on this foundation with faster build times and better caching mechanisms.</p>
</li>
</ul>
<p>Each iteration of Next.js has progressively built on the previous one, and Next.js 14 is no exception. It represents a culmination of the best features from earlier versions, refined and enhanced to meet the evolving needs of developers.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Next.js 14 represents a significant leap forward in web development. With enhanced middleware capabilities, faster build times, improved image optimization, better TypeScript support, and advanced routing features, it offers a powerful toolkit for developers. As we've seen from the real-life examples, companies are already benefiting from these updates, making Next.js 14 a worthy upgrade for any project.</p>
<p>Whether you're building a new application from scratch or looking to improve an existing one, the framework provides the tools you need to create fast, efficient, and high-performing web applications.</p>
]]></content:encoded></item><item><title><![CDATA[The structure of my upcoming AI project's tech stack]]></title><description><![CDATA[This article belongs to the series - Supabase One for All

Introduction
In the world of modern web development, the choice of tools and libraries can make or break your application. It's not just about the aesthetics or the speed, but the ease of dev...]]></description><link>https://blog.aiherrera.com/the-structure-of-my-upcoming-ai-projects-tech-stack</link><guid isPermaLink="true">https://blog.aiherrera.com/the-structure-of-my-upcoming-ai-projects-tech-stack</guid><category><![CDATA[supabase]]></category><category><![CDATA[AI]]></category><category><![CDATA[vector embeddings]]></category><category><![CDATA[huggingface]]></category><category><![CDATA[transformers]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Tue, 10 Oct 2023 15:00:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718253494773/6ce7beec-a6fc-49db-9e3f-0644cb522f8c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>This article belongs to the series - <a target="_blank" href="https://blog.aiherrera.com/series/supabase-one-for-all">Supabase One for All</a></p>
</blockquote>
<h2 id="heading-introduction">Introduction</h2>
<p>In the world of modern web development, the choice of tools and libraries can make or break your application. It's not just about the aesthetics or the speed, but the ease of development, scalability, and integration capabilities that truly distinguish an application. In this article, we'll combine some of my favorite tools for web development: Next.js+TailwindCSS, Supabase, and the new kid in town, Hugging Face Transformers.js library.</p>
<p>Let's do a quick overview:</p>
<ul>
<li><p><a target="_blank" href="https://nextjs.org/docs">Next.js</a>, developed by Vercel, is a React-based framework that provides out-of-the-box solutions for rendering on the server side, static site generation, and more. It accelerates the development process, ensuring your application is fast and SEO-friendly from the get-go.</p>
</li>
<li><p><a target="_blank" href="https://supabase.io/docs">Supabase</a> is an open-source Firebase alternative that provides you with a database, authentication, real-time subscriptions, and an easy integration with <a target="_blank" href="https://huggingface.co/">Hugging Face</a>. It empowers developers to build applications with less boilerplate code and more focus on business logic. They introduced <a target="_blank" href="https://supabase.com/docs/guides/functions"><strong>Supabase Edge Functions</strong></a> last year, allowing developers to run serverless functions at the edge, closer to the users which reduced latency and enhanced performance and became particularly beneficial these days for AI computations that, in the past, may have necessitated round trips to central servers.</p>
</li>
<li><p>Lastly, <a target="_blank" href="https://huggingface.co/docs/transformers.js/main/en/index">Hugging Face Transformers.js</a> brings the power of machine-learning models directly to the browser. With the vast array of pre-trained models available, developers can easily embed advanced text processing capabilities into their applications.</p>
</li>
</ul>
<p><strong>A Brief Case Study</strong>: Consider <code>TextAnalyzerPro</code>, a hypothetical web application that allows users to input large blocks of text. The application then utilizes machine learning models to analyze the text's sentiment, extract key entities, and summarize its content. Built using Next.js, it boasts a sleek interface crafted with TailwindCSS. The backend is powered by Supabase, handling user data profiles, authentication, storing data in a vector database and ensuring real-time feedback. The core text processing is done using a pre-trained model from Hugging Face Transformers.js, executed directly in the browser for faster results 😎</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696912923120/932c0420-f00f-4e4b-b39d-80c9455fd81c.jpeg" alt class="image--center mx-auto" /></p>
<p>By the end of this article, you'll have a clear pathway on how to integrate all these technologies into a single, coherent, and powerful web application, much like <code>TextAnalyzerPro</code>.</p>
<h2 id="heading-setting-up-the-development-environment">Setting up the development environment</h2>
<p>Before we start coding, we need to set up our development environment. This involves creating a Next.js app, installing dependencies, configuring Supabase, and integrating everything.</p>
<h3 id="heading-create-next-app">Create-next-app</h3>
<p>First, we'll create a new Next.js project using <code>create-next-app</code>. This gives us a basic scaffolded app we can build on top of.</p>
<p>Run the following in an empty directory to generate a new project called <code>TextAnalyzerPro</code>:</p>
<pre><code class="lang-bash">npx create-next-app@latest

What is your project named? TextAnalyzerPro
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the default import <span class="hljs-built_in">alias</span> (@/*)? No / Yes
What import <span class="hljs-built_in">alias</span> would you like configured? @/*
</code></pre>
<p>By following the CLI instructions, you should be able to create a new Next.js boilerplate with a basic configuration. For a detailed walkthrough, refer to the <a target="_blank" href="https://nextjs.org/docs/getting-started/installation">official Next.js documentation</a>.</p>
<p>Next, we'll install the required libraries our app depends on:</p>
<pre><code class="lang-bash">npm install tailwindcss postcss autoprefixer @supabase/supabase-js @xenova/transformers
</code></pre>
<p>This adds:</p>
<ul>
<li><p>Autoprefixer - for handling vendor prefixes</p>
</li>
<li><p>Tailwind CSS - for styling purposes</p>
</li>
<li><p>PostCSS - for processing CSS</p>
</li>
<li><p>SupabaseJS - for accesing the Supabase's API</p>
</li>
<li><p>Transformers - for running pre-trained models</p>
</li>
</ul>
<p>I designed this example in under an hour, just to demonstrate how quickly you can get on track:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696923307820/4ed89c86-af9b-44f7-8517-63c4926eb3b3.png" alt class="image--center mx-auto" /></p>
<p>Here is a quick example of the message component:</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="a7faa76e662d2240cb316500ceaaa6be"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/aiherrera/a7faa76e662d2240cb316500ceaaa6be" class="embed-card">https://gist.github.com/aiherrera/a7faa76e662d2240cb316500ceaaa6be</a></div><p> </p>
<h3 id="heading-configuring-supabase">Configuring Supabase</h3>
<p>Before you can harness the features of Supabase, you need an account. Register at <a target="_blank" href="http://Supabase.io">Supabase.io</a></p>
<blockquote>
<p>If you haven't used Supabase yet or are just greeting the tech, check <a target="_blank" href="https://hashnode.com/post/clgt051ep00040amr2djpfed7">this introductory article</a>!</p>
</blockquote>
<p>After logging in, click on the <code>New Project</code> button, fill in the necessary details for your project. Once created, you will be provided with a URL and API key. Make a note of these; they will be crucial for connecting your Next.js application to Supabase.</p>
<p>Remember to check Supabase's <a target="_blank" href="https://supabase.io/docs/guides/platform">official guide</a> for an in-depth setup.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: I recommend installing the Supabase CLI globally. In my case, since I'm using a Mac, I would use the command: <code>brew install supabase/tap/supabase</code>. However, it can be installed on any <a target="_blank" href="https://github.com/supabase/cli#install-the-cli">popular platform</a>.</div>
</div>

<h3 id="heading-generate-embeddings-with-supabase-edge-functions">Generate embeddings with Supabase Edge Functions</h3>
<p>Supabase has also hosted on Hugging Face, a small <a target="_blank" href="https://huggingface.co/Supabase/gte-small"><strong>General Text Embeddings (GTE) model</strong></a> with power-ups <a target="_blank" href="https://onnxruntime.ai/"><strong>ONNX</strong></a> weights, making it compatible with the <a target="_blank" href="https://huggingface.co/docs/transformers.js/index"><strong>Transformers.js</strong></a> library as we mentioned before.</p>
<blockquote>
<p>Developing and debugging Edge Functions requires setting up a local development environment, check out <a target="_blank" href="https://hashnode.com/post/cln2aocb3000309la5x2f0cfb">this guide</a> on how to do so!</p>
</blockquote>
<hr />
<p><strong>🤔 But, wait a second, what the heck are embeddings?</strong></p>
<p>Embeddings are vector representations of text generated by machine learning models like BERT. Each word or piece of text gets converted into a vector of continuous numbers based on the model's understanding.</p>
<p>For example, the word "apple" may become:</p>
<p><code>[0.4, 0.2, -0.1, 0.7, ...]</code></p>
<p>These numerical vectors capture semantic meaning and relationships between words. Words with similar meanings will have similar embeddings.</p>
<p>Some key advantages of embeddings:</p>
<ul>
<li><p>Represent concepts mathematically so they can be easily processed by ML algorithms</p>
</li>
<li><p>Capture semantic similarities between words based on context</p>
</li>
<li><p>Low-dimensional representation of text that can be searched and clustered</p>
</li>
<li><p>Efficient way to represent and compare large volumes of text data</p>
</li>
<li><p>etc</p>
</li>
</ul>
<hr />
<p>This model also benefits from fewer dimensions (384), it is 4 times smaller compared to popular models like OpenAI's <code>text-embedding-ada-002</code> and even ranks higher on the MTEB leaderboard. There is a detailed article explaining why <a target="_blank" href="https://supabase.com/blog/fewer-dimensions-are-better-pgvector#benefits-of-fewer-dimensions"><strong>fewer dimensions are better</strong></a> on their blog that I recommend consulting.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696832676193/44482be1-8003-4698-8932-fc3dfe5979db.png?auto=compress,format&amp;format=webp" alt /></p>
<p>which directly translates into:</p>
<ul>
<li><p>Fewer calculations for each computed distance</p>
</li>
<li><p>Reduced-cost usage</p>
</li>
</ul>
<p>With that in mind, let's generate our embeddings by invoking the GTE model within an EDGE Function.</p>
<blockquote>
<p><strong><em>If you don't know how to create an EDGE Function in Supabase, I have a</em></strong> <a target="_blank" href="https://blog.aiherrera.com/the-ultimate-guide-to-supabase-edge-functions"><strong><em>step-by-step article</em></strong></a> <strong><em>about how to do so, check it out!</em></strong></p>
</blockquote>
<p>This is the function I created to generate the embeddings and insert them into a vector database.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="63a0c2ca6081ce205e05abcb315b4fca"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/aiherrera/63a0c2ca6081ce205e05abcb315b4fca" class="embed-card">https://gist.github.com/aiherrera/63a0c2ca6081ce205e05abcb315b4fca</a></div><p> </p>
<p>Let's do a quick review:</p>
<ul>
<li><p>First, we import the required libraries that were configured in the <code>import_map.json</code> file.</p>
</li>
<li><p>Then, we retrieve the environment keys <code>SUPABASE_URL</code> and <code>SUPABASE_ANON_KEY</code> directly from the Deno environment, as these are variables exposed by the EDGE ecosystem.</p>
</li>
<li><p>We load the GTE model <code>Supabase/gte-small</code> hosted by Supabase into the pipeline.</p>
</li>
<li><p>Then pass the input to the pipeline to generate the embeddings and extract them from the output data</p>
</li>
<li><p>Finally, insert the generated embeddings into the vector database</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: If, while developing the function, you encounter a connection refusal error and have been attempting to execute your function, keep in mind that Supabase, for security reasons, bans any IP that repeatedly fails to establish a connection to the database.</div>
</div>

<p>To remove the ban just go to <code>Project Settings</code> <a target="_blank" href="https://emojipedia.org/right-arrow">➡️</a> <code>Database</code> <a target="_blank" href="https://emojipedia.org/right-arrow">➡️</a> <code>Banned IPs</code>. Search for yours and click on the right-side button that says unban IP.</p>
<h3 id="heading-how-to-create-a-vector-database-in-supabase">How to create a vector database in Supabase?</h3>
<p>To achieve this we are gonna create a migration with the following command in our project:</p>
<pre><code class="lang-bash"><span class="hljs-comment">## I have called initial_schema, but you can call it as you want</span>
supabase migrations new initial_schema
</code></pre>
<p>this command is gonna generate an empty <code>.sql</code> file, you can create something similar to:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> extension vector <span class="hljs-keyword">with</span> <span class="hljs-keyword">schema</span> extensions;

<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> collections (
    <span class="hljs-keyword">id</span> <span class="hljs-built_in">SERIAL</span> PRIMARY <span class="hljs-keyword">KEY</span>,
    embedding vector(<span class="hljs-number">384</span>)
);

<span class="hljs-keyword">create</span> <span class="hljs-keyword">index</span> <span class="hljs-keyword">on</span> collections <span class="hljs-keyword">using</span> hnsw (embedding vector_cosine_ops);
</code></pre>
<p><a target="_blank" href="https://supabase.com/vector">Supabase vector</a> experienced a significant performance improvement, as announced on the 6th of September, with the addition of pgvector v0.5.0 and the HNSW (Hierarchical Navigable Small World) index. More information can be found on their <a target="_blank" href="https://supabase.com/blog/increase-performance-pgvector-hnsw">blog</a>. And that's what we are using here:</p>
<ol>
<li><p>First, we enable the vector extension.</p>
</li>
<li><p>Afterward, we can create a table that includes a column of the vector type.</p>
</li>
<li><p>Finally, we create an index utilizing the HNSW index 😅</p>
</li>
</ol>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: The <code>vector(384)</code> displayed in the embedding column represents the dimensional quantities associated with the GTE model we previously discussed. Remember, fewer dimensions are better.</div>
</div>

<p>Now, when you call the function, your table should populate with something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696927432783/c74ef355-f39b-4ea5-b9d1-a99936be3486.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-use-cases">Use cases</h3>
<p>Up to this point, numerous potential use cases can be followed:</p>
<ul>
<li><p><strong>Semantic search</strong> - Store embeddings for documents/pages. Then search by converting the query to embedding and finding the closest matches.</p>
</li>
<li><p><strong>Content recommendations</strong> - Embed user history and products. Recommend items with similar embeddings.</p>
</li>
<li><p><strong>Sentiment analysis</strong> - Pass text through the sentiment classifier model to embed "positive" or "negative" sentiment.</p>
</li>
<li><p><strong>Chatbots</strong> - Embed user input and bot responses to select the most appropriate reply.</p>
</li>
<li><p><strong>Summarization</strong> - Generate embeddings for sentences in articles. Select sentences with embeddings closest to the overall article embedding as a summary.</p>
</li>
<li><p><strong>Clustering</strong> - Embed documents/users then cluster using K-means or hierarchical clustering to find groups.</p>
</li>
<li><p><strong>Information retrieval</strong> - Embed query and candidate passages. Return to most similar passages.</p>
</li>
<li><p><strong>Text generation</strong> - Embed initial text, and pass it to the generator model to get autocompletion matching the embedding.</p>
</li>
<li><p><strong>Spam detection</strong> - Classify texts as spam/not spam. Embed samples to train the classifier model.</p>
</li>
<li><p><strong>Language detection</strong> - Embed text samples from different languages. Build a model to classify language based on embedding proximity.</p>
</li>
</ul>
<h3 id="heading-examples">Examples</h3>
<p>Let's take the <code>TextAnalyzerPro</code> example from the beginning:</p>
<p>Imagine users submitting the following text data related to their customer support experience:</p>
<ol>
<li><p><strong>Text A</strong>: "I loved the latest version of the software. It has become more user-friendly and intuitive."</p>
</li>
<li><p><strong>Text B</strong>: "The customer support was very unhelpful and dismissive. I'm thinking of switching to another service."</p>
</li>
</ol>
<p>Processing the Data:</p>
<ol>
<li><p><strong>Generating Embeddings</strong>:</p>
<p> When these texts are submitted to <code>TextAnalyzerPro</code>, Supabase Edge Functions, with the help of the GTE Small model, convert them into embeddings. These embeddings capture the semantic essence of each text as can be described in the next scenarios:</p>
</li>
<li><p><strong>Sentiment Analysis</strong>:</p>
<p> Using a pre-trained model like BERT or RoBERTa, the embeddings are analyzed for sentiment:</p>
<ul>
<li><p><strong>Text A</strong>: Positive</p>
</li>
<li><p><strong>Text B</strong>: Negative</p>
</li>
</ul>
</li>
<li><p><strong>Entity Extraction</strong>:</p>
<p> Identifying key entities or themes in each text:</p>
<ul>
<li><p><strong>Text A</strong>: Entities extracted: ["latest version", "software", "user-friendly", "intuitive"]</p>
</li>
<li><p><strong>Text B</strong>: Entities extracted: ["customer support", "unhelpful", "dismissive", "another service"]</p>
</li>
</ul>
</li>
<li><p><strong>Summarization</strong>:</p>
<p> Generating concise summaries of the submitted texts:</p>
<ul>
<li><p><strong>Text A</strong>: "The user praises the software's latest version for its enhanced user-friendliness."</p>
</li>
<li><p><strong>Text B</strong>: "The user is unhappy with the customer support and is considering switching services."</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<p>That covers the basis of how to build a modern web application from start to finish with Next.js, Supabase and Hugging Face technologies! They provide the essentials for great performance, user experience, infrastructure and AI capabilities.</p>
<p>By combining reusable components, intelligent APIs and global CDN hosting, we can develop full-stack apps faster than ever.</p>
<p>The entire stack is free and open source, enabling rapid prototyping and iteration.</p>
<p>There's lots of room for additional features like real-time subscriptions, analytics, and more built on this stack - so stay tuned for upcoming articles!</p>
<h2 id="heading-potential-improvements-and-extensions">Potential improvements and extensions</h2>
<p>Here are some ideas for enhancing the application even further:</p>
<ol>
<li><p>Implement real-time functionality with Supabase subscriptions for instant updates.</p>
</li>
<li><p>Add a voting or commenting system for users to interact with posts.</p>
</li>
<li><p>Analyze text with Hugging Face's sentiment analysis to detect tone.</p>
</li>
<li><p>Create user profiles and avatars for more personalization.</p>
</li>
<li><p>Add search and filtering so users can easily find posts.</p>
</li>
<li><p>Build a recommendation system to suggest content to users.</p>
</li>
<li><p>Implement analytics to track page views, interactions, and conversions.</p>
</li>
<li><p>Support editing and deleting posts to keep content up-to-date.</p>
</li>
<li><p>Add rich media embedding for videos, images, and other media.</p>
</li>
<li><p>Build a mobile app version using React Native to complement the web.</p>
</li>
</ol>
<h2 id="heading-encouraging-further-exploration-and-learning">Encouraging further exploration and learning</h2>
<p>This article provided an overview of building an app with these technologies, but there's always more to learn. Here are some resources for leveling up your skills:</p>
<ul>
<li><p>Next.js Docs - <a target="_blank" href="https://nextjs.org/docs"><strong>https://nextjs.org/docs</strong></a></p>
</li>
<li><p>Supabase Docs - <a target="_blank" href="https://supabase.com/docs"><strong>https://supabase.com/docs</strong></a></p>
</li>
<li><p>Hugging Face Docs - <a target="_blank" href="https://huggingface.co/docs/transformers.js/main/en/index">Transformers.js</a></p>
</li>
<li><p>Next.js Learn Course - <a target="_blank" href="https://nextjs.org/learn"><strong>https://nextjs.org/learn</strong></a></p>
</li>
<li><p>Supabase YouTube - <a target="_blank" href="https://www.youtube.com/supabase"><strong>https://www.youtube.com/channel/UCJ9jj5YMzo-HsyM6WG9Q_Lg</strong></a></p>
</li>
</ul>
<p>Start building! Applying these frameworks to your projects is the best way to reinforce what you've learned. And don't hesitate to dive into the documentation or communities when you need help.</p>
<p>Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Transfer Your Local PostgreSQL Database to Supabase]]></title><description><![CDATA[Introduction
Recently, I've seen many people asking how to move their PostgreSQL database to Supabase. They want a clear guide to help them switch without losing data or causing too much downtime. The process is straightforward, let me show you!
Prer...]]></description><link>https://blog.aiherrera.com/transfer-your-local-postgresql-database-to-supabase</link><guid isPermaLink="true">https://blog.aiherrera.com/transfer-your-local-postgresql-database-to-supabase</guid><category><![CDATA[supabase]]></category><category><![CDATA[PostgreSQL]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Fri, 06 Oct 2023 07:10:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718254049621/51362210-3402-46bf-ac51-21fb819d4138.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Recently, I've seen many people asking how to move their PostgreSQL database to Supabase. They want a clear guide to help them switch without losing data or causing too much downtime. The process is straightforward, let me show you!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p>A local/remote PostgreSQL database you wanna migrate to Supabase.</p>
</li>
<li><p>A Supabase account (you can <a target="_blank" href="https://supabase.com/dashboard/sign-up">sign up</a> for free).</p>
</li>
<li><p>Basic knowledge of <a target="_blank" href="https://www.postgresqltutorial.com/postgresql-cheat-sheet/">PostgreSQL commands</a>.</p>
</li>
</ul>
<p>For this example, I have created a table called User with the fields: <code>id</code>, <code>name</code>, <code>lastname</code> and <code>age</code>, really simple, just for demonstration purposes:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696574572040/73694ea8-fe70-4adc-9783-dee30c5280b9.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-step-by-step-guide-to-migrating-your-database">Step-by-Step Guide to Migrating Your Database</h2>
<h3 id="heading-backup-your-local-database">Backup Your Local Database</h3>
<p>Before making any changes, it's crucial to back up your local database to prevent any data loss.</p>
<p>Use the <a target="_blank" href="https://www.postgresql.org/docs/current/app-pgdump.html"><code>pg_dump</code></a> command:</p>
<pre><code class="lang-bash">pg_dump <span class="hljs-string">'postgres://{user}:{password}@{hostname}:{port}/{database-name}'</span> &gt; database_dump.dump
</code></pre>
<p>Replace the placeholders with your local database details.</p>
<p>Alternatively, you can use any app that allows you to manage databases like <a target="_blank" href="https://tableplus.com/">TablePlus</a>, which is the one I'll be using in this example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696572775334/4a97f140-fc2a-4850-8a0a-99ba599cdae8.png" alt class="image--center mx-auto" /></p>
<p>As you can see I have two connections one pointing to my local database and another to the Supabase remote connection. To create a dump just click on the <code>Backup</code> option, select the local connection, and the database name and click the <code>Start backup</code> button as shown in the picture:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696573006923/dac7c0ca-fa98-4f0f-b809-84d5c985960a.png" alt class="image--center mx-auto" /></p>
<p>This will ask you to save a <code>.dump</code> file.</p>
<h3 id="heading-create-a-new-supabase-project">Create a New Supabase Project</h3>
<p>The next step would be the Backup importation. For this, we'll need to have a Supabase account created, if you already have one:</p>
<ul>
<li><p>Navigate to the <a target="_blank" href="https://app.supabase.io/">Supabase Dashboard</a>.</p>
</li>
<li><p>Click on "New Project" and fill in the required details.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696573295036/4c1b369e-648c-41a6-87a8-daf7202f9e87.png" alt class="image--center mx-auto" /></p>
<p>If you're having trouble with it, I have a <a target="_blank" href="https://hashnode.com/post/clgt051ep00040amr2djpfed7">Supabase starter guide</a> that will assist you in completing the task.</p>
<h3 id="heading-restore-the-backup-to-supabase">Restore the Backup to Supabase</h3>
<p>Now, you'll upload the backup to Supabase.</p>
<p>Use the <a target="_blank" href="https://www.postgresql.org/docs/current/app-pgrestore.html">pg_restore</a> command:</p>
<pre><code class="lang-bash">pg_restore -d <span class="hljs-string">'postgres://{user}:{password}@{hostname}:{port}/{database-name}'</span> database_dump.dump
</code></pre>
<p>Replace the placeholders with the details provided by Supabase for your project and the path to your backup file.</p>
<p>Again, you can achieve this with TablePlus easily and the steps are mostly identical to the dump process. This time click on the <code>Restore</code> option, select the previously created Supabase connection, and the database name and click the <code>Start restore</code> button as shown in the picture:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696574810921/2cf6ad98-0d1f-4789-bb7a-b0e0f5df71ac.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-verify-the-migration">Verify the Migration</h3>
<p>After the restoration process, navigate to the <code>Table</code> section in your Supabase dashboard. You'll see there all the tables of your database.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696574880996/0ded8349-de80-4670-8e93-58c40a9a59ed.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro Tip: Browse through the tables to ensure that the data matches your local database. I have only one table due to the demonstration, but you should ensure that all tables and relations between them as well as the data are consistent against your old database.</div>
</div>

<h3 id="heading-adjust-settings-amp-permissions">Adjust Settings &amp; Permissions</h3>
<p>Supabase provides a robust role-based permission system as you could see in the previous step. Make sure you set the correct permissions to each table in your database, it will make it more secure</p>
<ul>
<li><p>Go to the "Authentication" section.</p>
</li>
<li><p>Adjust the roles and permissions to match your application's requirements.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696575203807/88fa4436-5adf-4cd4-839d-b7824cf6ccde.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-update-your-applications-connection-strings">Update Your Application's Connection Strings</h3>
<p>If you have an application using the database:</p>
<ul>
<li><p>Update the connection strings to point to the Supabase database.</p>
</li>
<li><p>Test the application to ensure data retrieval and other operations work seamlessly.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>That's it!</p>
<p>Migrating your local PostgreSQL database to Supabase is a straightforward process that can offer numerous benefits, including scalability, real-time capabilities, and a user-friendly interface. By following the steps outlined in this article, you can smoothly transition your database to the cloud and leverage the power of Supabase for your projects.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro Tip: <em>Always ensure you have backups of your data before performing any migrations. If you encounter any issues, the </em><a target="_new" href="https://supabase.io/docs"><em>Supabase documentation</em></a><em> and community are excellent resources for assistance.</em></div>
</div>]]></content:encoded></item><item><title><![CDATA[Enhancing User Experience: The Power of Supabase Auth UI]]></title><description><![CDATA[Introduction
In today's digital world, user experience is key to the success of any web or mobile application. Users expect seamless, intuitive, and secure authentication processes that protect their personal information. That's where Supabase Auth U...]]></description><link>https://blog.aiherrera.com/enhancing-user-experience-the-power-of-supabase-auth-ui</link><guid isPermaLink="true">https://blog.aiherrera.com/enhancing-user-experience-the-power-of-supabase-auth-ui</guid><category><![CDATA[supabase]]></category><category><![CDATA[auth ui]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Wed, 04 Oct 2023 23:55:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718254083424/b175cbcd-5abd-40ab-850a-7adab5f88552.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In today's digital world, user experience is key to the success of any web or mobile application. Users expect seamless, intuitive, and secure authentication processes that protect their personal information. That's where <a target="_blank" href="https://supabase.com/docs/guides/auth/auth-helpers/auth-ui">Supabase Auth UI</a> comes in.</p>
<p>This powerful tool offers a comprehensive set of authentication features that not only enhance user experience but also prioritize cybersecurity. With Supabase Auth UI, developers can easily implement user authentication, manage user accounts, and customize the authentication flow to fit their specific application's needs.</p>
<p>In this article, we will explore the benefits of Supabase Auth UI and how it can transform the authentication process for developers and users alike.</p>
<p><img src="https://images.unsplash.com/photo-1508921340878-ba53e1f016ec?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxNjUwODR8MHwxfHNlYXJjaHwxfHwlMjB1c2VyJTIwb25ib2FyZGluZ3xlbnwwfDB8fHwxNjk2NDQ1NTY0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" alt="https://unsplash.com/@bugsster" /></p>
<blockquote>
<p>If you are new to Supabase or haven't read my previous articles about it, I recommend checking them out 😎:</p>
<ul>
<li><p><a target="_blank" href="https://hashnode.com/post/clgt051ep00040amr2djpfed7">Getting Started with Supabase: A Comprehensive Guide for Developers</a></p>
</li>
<li><p><a target="_blank" href="https://hashnode.com/post/clgt1gqr900040akzh2dmfe0v">The Ultimate Guide to Supabase Edge Functions</a></p>
</li>
<li><p><a target="_blank" href="https://hashnode.com/post/clh3prwxb000009ky2v1d0ipm">Unleash the power of automation by scheduling Supabase Edge Functions</a></p>
</li>
<li><p><a target="_blank" href="https://hashnode.com/post/cln2aocb3000309la5x2f0cfb">How to set up a Local Development environment for Supabase</a></p>
</li>
</ul>
</blockquote>
<h2 id="heading-understanding-the-significance-of-user-experience">Understanding the significance of user experience</h2>
<p>User experience (UX) plays a significant role in the success of any web or mobile application. It encompasses every interaction a user has with an application, from initial login to completing tasks and navigating through different features. A seamless and intuitive authentication process is crucial in ensuring a positive user experience.</p>
<blockquote>
<p>Most business models have focused on self-interest instead of user experience.</p>
<p>-Tim Cook</p>
</blockquote>
<p>When users encounter complicated or time-consuming authentication procedures, they may lose interest and abandon the application altogether. Supabase Auth UI understands the significance of delivering a smooth authentication experience to users. By simplifying the authentication flow and providing intuitive interfaces, it minimizes user frustration and enhances engagement.</p>
<p>Furthermore, Supabase Auth UI prioritizes cybersecurity, offering robust security measures to protect user information. By implementing industry-standard security practices, developers can ensure the safety and trustworthiness of their applications, resulting in enhanced user confidence.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696449091461/8808b7f8-2bd5-4236-88ce-6c865dc0aae2.png" alt class="image--center mx-auto" /></p>
<p>In the next section, we will delve deeper into the specific features of Supabase Auth UI and how they contribute to an enriched user experience. Stay tuned to discover the power of this authentication tool!</p>
<h2 id="heading-introducing-supabase-auth-ui-and-its-capabilities">Introducing Supabase Auth UI and its capabilities</h2>
<p>Supabase Auth UI is a powerful authentication tool that brings a range of capabilities to enhance user experience. With its intuitive interfaces and simplified authentication flow, this tool ensures a frictionless user journey from login to completing tasks within the application.</p>
<p>One of the standout features of Supabase Auth UI is its customization options. Developers can easily adapt the authentication process to fit the look and feel of their application, providing a seamless transition for users. This level of personalization allows developers to maintain brand consistency and create a cohesive user experience.</p>
<p>Another noteworthy capability of Supabase Auth UI is its support for various third-party authentication providers, including Google, Apple, and GitHub. This integration increases convenience for users who prefer using existing accounts to log in, providing them with a hassle-free authentication experience.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// example of third party authentication providers </span>
<span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/supabase-js'</span>
<span class="hljs-keyword">import</span> { Auth } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/auth-ui-react'</span>
<span class="hljs-keyword">import</span> { ThemeSupa } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/auth-ui-shared'</span>

<span class="hljs-keyword">const</span> supabase = createClient(<span class="hljs-string">'&lt;INSERT PROJECT URL&gt;'</span>, <span class="hljs-string">'&lt;INSERT PROJECT ANON API KEY&gt;'</span>)

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Auth</span>
    <span class="hljs-attr">supabaseClient</span>=<span class="hljs-string">{supabase}</span>
    <span class="hljs-attr">providers</span>=<span class="hljs-string">{[</span>'<span class="hljs-attr">google</span>', '<span class="hljs-attr">facebook</span>', '<span class="hljs-attr">twitter</span>', <span class="hljs-attr">etc...</span>]}
  /&gt;</span></span>
)
</code></pre>
<p>Furthermore, Supabase Auth UI offers developer-friendly APIs that facilitate quick and efficient integration. Developers can leverage these APIs to build custom authentication workflows or extend the functionality of the authentication process.  </p>
<p>We'll be covering this in upcoming articles ✍️</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">signInWithEmail</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase.auth.signInWithPassword({
    <span class="hljs-attr">email</span>: <span class="hljs-string">'johndoe@gmail.com'</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-string">'strong-password'</span>,
  })
}
</code></pre>
<h3 id="heading-simplifying-user-onboarding">Simplifying user onboarding</h3>
<p>One of the key challenges that developers face when building applications is ensuring a smooth onboarding experience for users. This is where Supabase Auth UI truly shines. With its user-friendly interfaces and simplified authentication flow, it takes the hassle out of user onboarding.</p>
<pre><code class="lang-bash">// installing libraries
npm install @supabase/supabase-js @supabase/auth-ui-react @supabase/auth-ui-shared
</code></pre>
<p>Supabase Auth UI provides a seamless authentication process that guides users through the necessary steps, from creating an account to verifying their email address. The intuitive interfaces make it easy for users to understand and complete each task, reducing the chances of confusion or abandonment.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// basic example of powering up your App with the Auth component</span>
<span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/supabase-js'</span>
<span class="hljs-keyword">import</span> { Auth } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/auth-ui-react'</span>

<span class="hljs-keyword">const</span> supabase = createClient(<span class="hljs-string">'&lt;INSERT PROJECT URL&gt;'</span>, <span class="hljs-string">'&lt;INSERT PROJECT ANON API KEY&gt;'</span>)

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Auth</span> <span class="hljs-attr">supabaseClient</span>=<span class="hljs-string">{supabase}</span> /&gt;</span></span>j
</code></pre>
<p>Additionally, as we mentioned above, Supabase Auth UI offers features such as passwordless authentication and social login options, further streamlining the onboarding process. Users can choose the authentication method that suits them best, whether it's receiving a <a target="_blank" href="https://supabase.com/docs/guides/auth/auth-magic-link">one-time password</a> via email or logging in with their <a target="_blank" href="https://supabase.com/docs/guides/auth/social-login#set-up-a-social-provider-with-supabase-auth">Google or Apple account among many other options.</a></p>
<h3 id="heading-increasing-security-and-trust">Increasing security and trust</h3>
<p>When it comes to user authentication, security is of paramount importance. Thankfully, Supabase Auth UI excels in this aspect by providing robust security features that enhance user trust and safeguard sensitive information.</p>
<p>Supabase Auth UI supports industry-standard security protocols, such as the use of password hashing and salting to protect user passwords. This ensures that user credentials are securely stored and transmitted, reducing the risk of unauthorized access.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696451461473/94e93fa5-5b4e-48d5-9519-e6ab02ee279a.png" alt class="image--center mx-auto" /></p>
<p>Additionally, Supabase Auth UI offers <a target="_blank" href="https://supabase.com/docs/guides/auth/auth-mfa">multi-factor authentication (MFA)</a> capabilities, allowing developers to implement an extra layer of security. With MFA, users have to provide a verification code, generated on their trusted device, in addition to their username and password. This significantly reduces the likelihood of unauthorized access, adding an extra level of confidence for both developers and users.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696451602937/d24a0d6d-9ff1-498a-95f4-e17ac9a704d0.png" alt class="image--center mx-auto" /></p>
<p>By prioritizing security, Supabase Auth UI reinforces the trust users have in the application and builds a solid foundation for a secure user experience. In the next section, we will dive deeper into the customization options offered by Supabase Auth UI, allowing developers to seamlessly integrate authentication into their application's unique design and branding.</p>
<h3 id="heading-customizing-and-branding-your-user-interface">Customizing and branding your user interface</h3>
<p>Customizing and branding your user interface with Supabase Auth UI is a breeze. This powerful authentication tool provides developers with a range of options to seamlessly integrate the authentication process into their application's unique design and branding.</p>
<p>With Supabase Auth UI, you can customize the look and feel of the user interface to ensure it aligns perfectly with your application's aesthetics. You can easily customize colors, and fonts, and even add your logos and images to create a cohesive and branded experience for your users.</p>
<p>Let's take the following example where you can customize the appearance by using a custom predefined theme and even a dark theme variation:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// </span>
<span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/supabase-js'</span>
<span class="hljs-keyword">import</span> { Auth } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/auth-ui-react'</span>
<span class="hljs-keyword">import</span> { ThemeSupa } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/auth-ui-shared'</span>

<span class="hljs-keyword">const</span> supabase = createClient(
  <span class="hljs-string">'&lt;INSERT PROJECT URL&gt;'</span>,
  <span class="hljs-string">'&lt;INSERT PROJECT ANON API KEY&gt;'</span>
)

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Auth</span>
    <span class="hljs-attr">supabaseClient</span>=<span class="hljs-string">{supabase}</span>
    <span class="hljs-attr">appearance</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">theme:</span> <span class="hljs-attr">ThemeSupa</span> }}
    <span class="hljs-attr">theme</span>=<span class="hljs-string">"dark"</span>
  /&gt;</span></span>
)
</code></pre>
<p>You can, of course, add custom CSS styles and create your own theme:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> customTheme = {
  <span class="hljs-attr">default</span>: {
    <span class="hljs-attr">colors</span>: {
      <span class="hljs-attr">brand</span>: <span class="hljs-string">'hsl(153 60.0% 53.0%)'</span>,
      <span class="hljs-attr">brandAccent</span>: <span class="hljs-string">'hsl(154 54.8% 45.1%)'</span>,
      <span class="hljs-attr">brandButtonText</span>: <span class="hljs-string">'white'</span>,
      <span class="hljs-comment">// ..</span>
    },
  },
  <span class="hljs-attr">dark</span>: {
    <span class="hljs-attr">colors</span>: {
      <span class="hljs-attr">brandButtonText</span>: <span class="hljs-string">'white'</span>,
      <span class="hljs-attr">defaultButtonBackground</span>: <span class="hljs-string">'#2e2e2e'</span>,
      <span class="hljs-attr">defaultButtonBackgroundHover</span>: <span class="hljs-string">'#3e3e3e'</span>,
      <span class="hljs-comment">//..</span>
    },
  },
  <span class="hljs-comment">// You can also add more theme variations with different names.</span>
  <span class="hljs-attr">evenDarker</span>: {
    <span class="hljs-attr">colors</span>: {
      <span class="hljs-attr">brandButtonText</span>: <span class="hljs-string">'white'</span>,
      <span class="hljs-attr">defaultButtonBackground</span>: <span class="hljs-string">'#1e1e1e'</span>,
      <span class="hljs-attr">defaultButtonBackgroundHover</span>: <span class="hljs-string">'#2e2e2e'</span>,
      <span class="hljs-comment">//..</span>
    },
  },
}
</code></pre>
<p>Furthermore, Supabase Auth UI offers a range of pre-built UI components, making it easy to create a visually appealing and user-friendly authentication flow. Whether you need login forms, password reset forms, or magic links, Supabase Auth UI has you covered.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696454435902/f491d732-f397-45b6-9349-36ac4e7b9f88.png" alt class="image--center mx-auto" /></p>
<p>In addition to customization options, Supabase Auth UI also supports localization. You can easily translate your user interface into different languages, ensuring a seamless experience for users around the world. It is as easy as creating a file for each required language by overriding the <a target="_blank" href="https://github.com/supabase/auth-ui/blob/main/packages/shared/src/localization/en.json">localization variables available</a>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/supabase-js'</span>
<span class="hljs-keyword">import</span> { Auth } <span class="hljs-keyword">from</span> <span class="hljs-string">'@supabase/auth-ui-react'</span>
<span class="hljs-keyword">import</span> { fr } <span class="hljs-keyword">from</span> <span class="hljs-string">'./i18n'</span>

<span class="hljs-keyword">const</span> supabase = createClient(<span class="hljs-string">'&lt;INSERT PROJECT URL&gt;'</span>, <span class="hljs-string">'&lt;INSERT PROJECT ANON API KEY&gt;'</span>)

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Auth</span>
    <span class="hljs-attr">supabaseClient</span>=<span class="hljs-string">{supabase}</span>
    <span class="hljs-attr">localization</span>=<span class="hljs-string">{fr}</span>
  /&gt;</span></span>
)
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fr = {
  <span class="hljs-attr">variables</span>: {
    <span class="hljs-attr">sign_in</span>: {
      <span class="hljs-attr">email_label</span>: <span class="hljs-string">'Votre adresse e-mail'</span>,
      <span class="hljs-attr">password_label</span>: <span class="hljs-string">'Votre mot de passe fort'</span>,
      ...
    },
  }
}
</code></pre>
<p>With Supabase Auth UI's customization and branding options, you can create an authentication process that not only enhances the user experience but also reinforces your application's unique identity.</p>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<p>As we have explored in this blog series, Supabase Auth UI has the power to revolutionize user experiences by providing innovative features that ultimately enhance the way users interact with applications.</p>
<blockquote>
<p>In the next articles we will be covering server-side authentication APIs and other cool features about Supabase, so stay tuned!</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[How to set up a Local Development Environment for Supabase]]></title><description><![CDATA[Introduction
Supabase is an open-source alternative to Firebase that provides authentication, real-time databases, storage, and more through a PostgreSQL database. Setting up a local development environment allows you to build and test Supabase apps ...]]></description><link>https://blog.aiherrera.com/how-to-set-up-a-local-development-environment-for-supabase</link><guid isPermaLink="true">https://blog.aiherrera.com/how-to-set-up-a-local-development-environment-for-supabase</guid><category><![CDATA[supabase]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Wed, 27 Sep 2023 22:05:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695852044161/a03fa55e-f4d5-441d-9f4e-3ff11f7209b4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Supabase is an open-source alternative to Firebase that provides authentication, real-time databases, storage, and more through a PostgreSQL database. Setting up a local development environment allows you to build and test Supabase apps on your machine before deploying to production. In this post, we'll walk through the steps to get a local Supabase environment running on your computer.</p>
<p>If you are new to Supabase, check out these other posts about it:</p>
<ul>
<li><p><a target="_blank" href="https://hashnode.com/post/clgt051ep00040amr2djpfed7">Getting Started with Supabase: A Comprehensive Guide for Developers</a></p>
</li>
<li><p><a target="_blank" href="https://hashnode.com/post/clgt1gqr900040akzh2dmfe0v">The ultimate guide to Supabase Edge Functions</a></p>
</li>
<li><p><a target="_blank" href="https://hashnode.com/post/clh3prwxb000009ky2v1d0ipm">Unleash the power of automation by scheduling Supabase Edge Functions</a></p>
</li>
</ul>
<p>😎 As stated on their website, there are several benefits to being able to accomplish this:</p>
<ol>
<li><p>🚀 <strong>Faster Development</strong>: Developing locally allows you to work without any network latency or internet disruptions.</p>
</li>
<li><p>💬 <strong>Easier Collaboration</strong>: Developing locally can make it easier to collaborate with others on the same project.</p>
</li>
<li><p>🤑 <strong>Cost-Effective</strong>: Supabase provides a generous free plan and gives you two free projects to get started. But what if you need more than two? When you develop locally, you can spin up unlimited local projects and link them with live projects when you're ready to launch.</p>
</li>
<li><p>🛠️ <strong>Configuration in code</strong>: If you directly change your tables via the Dashboard, none of that gets captured in code. If you follow these local development practices, you'll store all of your table schemas in code.</p>
</li>
<li><p>🚂 <strong>Work offline</strong>: Need to work from a train? A plane? An automobile? No problem. Developing your project locally allows you to work offline.</p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To set up a Supabase local environment, you will need to have some tools installed beforehand:</p>
<ul>
<li><p><a target="_blank" href="https://git-scm.com/">Git</a></p>
</li>
<li><p><a target="_blank" href="https://www.docker.com/">Docker</a></p>
</li>
<li><p><a target="_blank" href="https://www.docker.com/products/docker-desktop/">Docker Compose</a></p>
</li>
</ul>
<p>These tools allow us to easily spin up the PostgreSQL database and other services needed for Supabase.</p>
<h2 id="heading-installing-supabase-cli">Installing Supabase CLI</h2>
<p>The next step would be installing <a target="_blank" href="https://github.com/supabase/cli">Supabase CLI</a> to have access to a sort of useful commands, in my case I'll be installing it on a Mac but it can be installed pretty much on every platform:</p>
<pre><code class="lang-bash">brew install supabase/tap/supabase
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695840915681/0876eb48-5450-4778-95d1-f1421a35674e.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-setting-up-a-project">Setting up a project</h2>
<p>Now let's create a project using this <a target="_blank" href="https://github.com/aiherrera/vite-react-starter-template">Vite template</a> for a quick-started POC project that I shared in <a target="_blank" href="https://blog.aiherrera.com/vite-based-starter-kit-for-react-apps-without-using-frameworks">this post</a>.</p>
<p>Then let's clone the just-created project:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/aiherrera/whatever-name-you-choose
</code></pre>
<p>You should get something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695841553658/b077174d-79ad-4fd1-b160-9a45dd06a728.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: if you opt-in for not cloning the project and just start from scratch, keep in mind that you'll have to init a git project manually inside your project folder - aka: <code>git init</code></div>
</div>

<p>Now, initialize Supabase to set up the configuration for developing your project locally, on the root of your project folder run:</p>
<pre><code class="lang-bash">supabase init
Generate VS Code workspace settings? [y/N] N
Finished supabase init.
</code></pre>
<p>Then run the start command: the start command uses Docker to start the Supabase services:</p>
<ul>
<li><p>PostgreSQL (Database): <em>PostgreSQL is the core of Supabase. It provides tools that make PostgreSQL as easy to use as Firebase.</em></p>
</li>
<li><p>Studio (Dashboard): <em>An open source Dashboard for managing your database and services.</em></p>
</li>
<li><p>GoTrue (Auth): <em>A JWT-based API for managing users and issuing access tokens. This integrates with PostgreSQL's Row Level Security and the API servers.</em></p>
</li>
<li><p>PostgREST (API): <em>A standalone web server that turns your PostgreSQL database directly into a RESTful API.</em></p>
</li>
<li><p>Realtime (API &amp; multiplayer): <em>A scalable WebSocket engine for managing user Presence, broadcasting messages, and streaming database changes.</em></p>
</li>
<li><p>Storage API (large file storage): <em>An S3-compatible object storage service that stores metadata in Postgres.</em></p>
</li>
<li><p><em>Deno (Edge Functions): A modern runtime for JavaScript and TypeScript.</em></p>
</li>
<li><p>postgres-meta (Database management): <em>A RESTful API for managing your Postgres. Fetch tables, add roles, and run queries.</em></p>
</li>
<li><p>PgBouncer: <em>A lightweight connection pooler for PostgreSQL. This is useful for connecting to Postgres when using Serverless functions.</em></p>
</li>
<li><p>Kong (API Gateway): <em>A cloud-native API gateway, built on top of Nginx.</em></p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: Make sure Docker is running 😎</div>
</div>

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: This command may take a while to run if this is the first time using the CLI. Underneath it will pull all the required services to make the Supabase Local environment work, so grab a cup of coffee ☕</div>
</div>

<p>Once finished pulling all images and setting up the environment you'll get all the local endpoints and secret keys to access Supabase Local.</p>
<pre><code class="lang-bash">supabase start
Seeding data supabase/seed.sql...
Started supabase <span class="hljs-built_in">local</span> development setup.

         API URL: http://localhost:54321
     GraphQL URL: http://localhost:54321/graphql/v1
          DB URL: postgresql://postgres:postgres@localhost:54322/postgres
      Studio URL: http://localhost:54323
    Inbucket URL: http://localhost:54324
      JWT secret: super-secret-jwt-token-with-at-least-32-characters-long
        anon key: eyJhbG...
service_role key: eyJhbG...
</code></pre>
<p>You can stop the Docker instance anytime by running this command:</p>
<pre><code class="lang-bash">supabase db stop
</code></pre>
<p>And can reset the database to its initial state by running:</p>
<pre><code class="lang-bash">supabase db reset
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: this is particularly useful once you have defined migrations and/or seeders and wanna get a fresh start for testing purposes for example.</div>
</div>

<h2 id="heading-publishing-changes-to-supabase">Publishing changes to Supabase</h2>
<p>Once you have more certainty about the shape of a more mature project, you can publish your local changes to your live instance of Supabase. This command will sync your database structure and data within the live one.</p>
<pre><code class="lang-bash">supabase db push
</code></pre>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<p>Upon successful completion of the setup process, you now have a fully operational instance of Supabase running locally on your machine. This local deployment offers several significant advantages that can enhance your overall development experience.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695845269647/e1d33706-6253-4563-a57c-af401722b07f.png" alt="Supabase Local instance up and running." class="image--center mx-auto" /></p>
<ul>
<li><p>First and foremost, by hosting Supabase locally, you can effectively reduce costs associated with cloud-based services. This cost-effective solution allows you to allocate resources more efficiently, ultimately saving you money in the long run.</p>
</li>
<li><p>Secondly, the local instance enables you to work offline, providing you with the flexibility to develop and test your applications even in the absence of an internet connection. This feature is particularly useful for developers who may find themselves in remote locations or areas with limited connectivity.</p>
</li>
<li><p>Lastly, the local Supabase instance ensures a high-speed development experience, as it eliminates any connection constraints that may arise from using a remote server. This results in a more seamless and efficient workflow, allowing you to focus on building and refining your applications without any unnecessary delays or interruptions.</p>
</li>
</ul>
<h3 id="heading-its-just-that-easy-happy-coding">It's just that easy, happy coding!</h3>
<p><img src="https://imgs.search.brave.com/TvVoPIeAFjjql_EiAsb0_iuQ1u7SYXAlSU1rl9GaflQ/rs:fit:860:0:0/g:ce/aHR0cHM6Ly93YWxs/cGFwZXJhY2Nlc3Mu/Y29tL2Z1bGwvMTMw/OTI1My5qcGc" alt="1366x768 Back To 84 Kung Fu Panda HD Wallpaper Fu Panda" class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Grasping the Object.groupBy Method in JavaScript]]></title><description><![CDATA[Introduction
JavaScript, as a dynamic and ever-evolving programming language, continues to introduce new features and enhancements to cater to the needs of developers. Among its most recent additions is the Object.groupBy method, is a powerful and ve...]]></description><link>https://blog.aiherrera.com/grasping-the-objectgroupby-method-in-javascript</link><guid isPermaLink="true">https://blog.aiherrera.com/grasping-the-objectgroupby-method-in-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Objects]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Fri, 15 Sep 2023 06:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695153475596/7f58256b-d5d7-4cc8-96ae-e6da48a1c7a2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>JavaScript, as a dynamic and ever-evolving programming language, continues to introduce new features and enhancements to cater to the needs of developers. Among its most recent additions is the <code>Object.groupBy</code> method, is a powerful and versatile tool that is still in its experimental phase. Although not yet universally supported across all web browsers, the <code>Object.groupBy</code> method provides a highly convenient means of grouping elements within an iterable based on a user-defined callback function. In this comprehensive article, we will explore the ins and outs of the <code>Object.groupBy</code> method, discussing its practical applications, compatibility with various browsers, and illustrating its usage through real-world examples.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695150162075/32ec890d-3845-4820-8519-92c95f9d536f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-what-is-objectgroupby">What is Object.groupBy?</h2>
<p>The <code>Object.groupBy</code> static method groups the elements of a given iterable according to the string values returned by a provided callback function. The returned object has separate properties for each group, containing arrays with the elements in the group.</p>
<h3 id="heading-syntax">Syntax</h3>
<pre><code class="lang-javascript"><span class="hljs-built_in">Object</span>.groupBy(items, callbackFn)
</code></pre>
<ul>
<li><p><strong>items</strong>: An iterable (such as an Array) whose elements will be grouped.</p>
</li>
<li><p><strong>callbackFn</strong>: A function to execute for each element in the iterable. It should return a value that can get coerced into a property key (string or symbol) indicating the group of the current element.</p>
</li>
</ul>
<h3 id="heading-return-value">Return value</h3>
<p>The method returns a null-prototype object with properties for all groups, each assigned to an array containing the elements of the associated group.</p>
<h2 id="heading-usage-examples">Usage examples</h2>
<h3 id="heading-grouping-by-type-grouping-students-by-grade-level">Grouping by type: Grouping students by grade level</h3>
<p>Imagine you're a school administrator and you have a list of students with their respective grade levels. You want to group these students by their grade levels to make it easier to manage activities or distribute resources. The <code>Object.groupBy</code> method can come in handy for this task.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> students = [
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Alice"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Freshman"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Bob"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Sophomore"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Charlie"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Junior"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"David"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Senior"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Eva"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Freshman"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Fiona"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Junior"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"George"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Senior"</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Hannah"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Sophomore"</span> }
];
<span class="hljs-comment">// Assuming Object.groupBy is available or polyfilled</span>
<span class="hljs-keyword">const</span> groupedStudents = <span class="hljs-built_in">Object</span>.groupBy(students, <span class="hljs-function">(<span class="hljs-params">{ grade }</span>) =&gt;</span> grade);

<span class="hljs-built_in">console</span>.log(groupedStudents);
</code></pre>
<p>This would be the expected result:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-attr">Freshman</span>: [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Alice"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Freshman"</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Eva"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Freshman"</span> }
  ],
  <span class="hljs-attr">Sophomore</span>: [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Bob"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Sophomore"</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Hannah"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Sophomore"</span> }
  ],
  <span class="hljs-attr">Junior</span>: [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Charlie"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Junior"</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Fiona"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Junior"</span> }
  ],
  <span class="hljs-attr">Senior</span>: [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"David"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Senior"</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"George"</span>, <span class="hljs-attr">grade</span>: <span class="hljs-string">"Senior"</span> }
  ]
}
</code></pre>
<p>With the students now grouped by grade level, you can easily:</p>
<ul>
<li><p>Distribute grade-specific resources or announcements.</p>
</li>
<li><p>Plan activities or events for each grade level.</p>
</li>
<li><p>Perform statistical analysis on each grade level.</p>
</li>
</ul>
<p>This is just one example, but the possibilities are endless. The <code>Object.groupBy</code> method provides a convenient and efficient way to group items in various real-world scenarios.</p>
<h3 id="heading-grouping-by-quantity-grouping-products-by-stock-availability">Grouping by Quantity: Grouping Products by Stock Availability</h3>
<p>Imagine you're managing an online store's inventory, and you want to quickly identify which products need to be restocked and which are in good supply. You can use the <code>Object.groupBy</code> method to group your products based on their stock quantity.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> products = [
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Laptop"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">10</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Smartphone"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">5</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Headphones"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">0</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Mouse"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">25</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Keyboard"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">3</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Monitor"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">7</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Webcam"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">0</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">"Microphone"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">15</span> }
];

<span class="hljs-comment">// Assuming Object.groupBy is available or polyfilled</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stockStatus</span>(<span class="hljs-params">{ quantity }</span>) </span>{
  <span class="hljs-keyword">if</span> (quantity === <span class="hljs-number">0</span>) <span class="hljs-keyword">return</span> <span class="hljs-string">"Out of Stock"</span>;
  <span class="hljs-keyword">if</span> (quantity &lt; <span class="hljs-number">5</span>) <span class="hljs-keyword">return</span> <span class="hljs-string">"Low Stock"</span>;
  <span class="hljs-keyword">return</span> <span class="hljs-string">"In Stock"</span>;
}

<span class="hljs-keyword">const</span> groupedProducts = <span class="hljs-built_in">Object</span>.groupBy(products, stockStatus);

<span class="hljs-built_in">console</span>.log(groupedProducts);
</code></pre>
<p>This would be the expected result:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"Out of Stock"</span>: [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Headphones"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Webcam"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">0</span> }
  ],
  <span class="hljs-string">"Low Stock"</span>: [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Smartphone"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">5</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Keyboard"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">3</span> }
  ],
  <span class="hljs-string">"In Stock"</span>: [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Laptop"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">10</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Mouse"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">25</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Monitor"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">7</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Microphone"</span>, <span class="hljs-attr">quantity</span>: <span class="hljs-number">15</span> }
  ]
}
</code></pre>
<p>With the products now grouped by their stock status, you can:</p>
<ul>
<li><p>Quickly identify items that need to be restocked.</p>
</li>
<li><p>Send low-stock alerts to the purchasing department.</p>
</li>
<li><p>Prioritize marketing for products that are in good supply.</p>
</li>
</ul>
<p>This example demonstrates how the <code>Object.groupBy</code> method can be a powerful tool for inventory management and other real-world applications.</p>
<h2 id="heading-browser-compatibility">Browser Compatibility</h2>
<p>As of now, the <code>Object.groupBy</code> method is not universally supported. Here's a quick rundown:</p>
<ul>
<li><p><strong>Chrome</strong>: Supported from version 117</p>
</li>
<li><p><strong>Edge</strong>: Supported from version 117</p>
</li>
<li><p><strong>Firefox</strong>: Not supported</p>
</li>
<li><p><strong>Safari</strong>: Supported from version 17.1</p>
</li>
<li><p><strong>Opera</strong>: Not supported</p>
</li>
</ul>
<blockquote>
<p><strong>Note: This feature is experimental. Use caution before using it in production.</strong></p>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695149852074/a47e48e0-388a-43c1-a1ee-b6f33f31470d.png" alt="Image from CanIUse" class="image--center mx-auto" /></p>
<h2 id="heading-final-thoughts"><strong>Final thoughts</strong></h2>
<p>The <code>Object.groupBy</code> method offers a convenient way to group elements of an iterable based on a callback function. While it's still experimental and not widely supported, it's a feature worth keeping an eye on as JavaScript continues to evolve.</p>
<p>For more information, you can refer to the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy"><strong>MDN Web Docs</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Mastering Vite Application Testing with Vitest: A simple guide to prevent  headaches]]></title><description><![CDATA[Introduction
Vite, a modern front-end build tool, has been gaining popularity due to its fast and lean development experience. Paired with Vitest, a testing framework designed specifically for Vite, you can create a robust testing environment for you...]]></description><link>https://blog.aiherrera.com/mastering-vite-application-testing-with-vitest-a-simple-guide-to-prevent-headaches</link><guid isPermaLink="true">https://blog.aiherrera.com/mastering-vite-application-testing-with-vitest-a-simple-guide-to-prevent-headaches</guid><category><![CDATA[vite]]></category><category><![CDATA[vitest]]></category><category><![CDATA[Testing Library]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Mon, 10 Jul 2023 05:37:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1688964781337/e85567aa-64b8-4258-9113-5dad5439282b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Vite, a modern front-end build tool, has been gaining popularity due to its fast and lean development experience. Paired with Vitest, a testing framework designed specifically for Vite, you can create a robust testing environment for your applications. In this blog post, we'll explore how to master Vite application testing with Vitest, complete with tips, tricks, and examples.</p>
<h2 id="heading-what-is-vite-and-vitest">What is Vite and Vitest?</h2>
<p><a target="_blank" href="https://vitejs.dev/">Vite</a> (French for "fast") is a next-generation front-end build tool created by Evan You, the creator of Vue.js. It offers a faster and leaner development experience for modern web projects.</p>
<p><a target="_blank" href="https://vitest.dev/">Vitest</a>, on the other hand, is a testing framework designed specifically for Vite. It provides a fast, scalable, and easy-to-use testing solution for Vite applications.</p>
<h2 id="heading-setting-up-your-vite-project">Setting Up Your Vite Project</h2>
<p>Before we dive into testing, let's set up a simple Vite project. Here's how you can create a new Vite project using the command line:</p>
<pre><code class="lang-bash">pnpm create vite
</code></pre>
<p>This command will provide some quick questions to generate a new project. This is the configuration I selected for the project:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688959199209/41c3ecb9-9d59-4ffd-9f72-8b3bf3c708ab.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: I use <code>pnpm</code> as my package manager. It is way more performant than the classic <code>npm</code>. Since there could be different opinions between developer preferences, I'll just let a <a target="_blank" href="https://pnpm.io/feature-comparison">comparison table</a> within the features of each package manager - pick the one you like the most 😜</div>
</div>

<h2 id="heading-installing-and-configuring-vitest">Installing and Configuring Vitest</h2>
<p>To install Vitest, run the following command in your project directory:</p>
<pre><code class="lang-bash">pnpm add -D vitest
</code></pre>
<p>Next, add these two <code>vitest</code> scripts to your <code>package.json</code>:</p>
<pre><code class="lang-bash"><span class="hljs-string">"scripts"</span>: {
  ...
  <span class="hljs-string">"test"</span>: <span class="hljs-string">"vitest"</span>,
  <span class="hljs-string">"coverage"</span>: <span class="hljs-string">"vitest run --coverage"</span>
}
</code></pre>
<p>Now, you can run your tests using <code>pnpm run test</code>.</p>
<p>Since Vitest is a unit testing framework for Vite, as you might have guessed by now, it integrates seamlessly with it. As stated on their website, Vitest can:</p>
<blockquote>
<p><strong>Reuse Vite's config, transformers, resolvers, and plugins - consistent across your app and tests.</strong></p>
</blockquote>
<p>In other words, this is all we need to begin creating Unit Tests for our project.</p>
<p>However, why stop here? Let's enhance our current toolkit with another fantastic tool!</p>
<p>For creating our tests, we will integrate <a target="_blank" href="https://testing-library.com/">Testing Library</a>, a very handy set of utilities that, as they state:</p>
<blockquote>
<p>The Testing Library family of libraries is a very light-weight solution for testing without all the implementation details. The main utilities it provides involve querying for nodes similarly to how users would find them. In this way, testing-library helps ensure your tests give you confidence in your UI code.</p>
</blockquote>
<p>So, let's install it:</p>
<pre><code class="lang-bash">pnpm add -D jsdom @testing-library/react
</code></pre>
<p>as you can see we are also installing <code>jsdom</code>:</p>
<p>To effectively test React components, it is essential to replicate the DOM functionality in the test environment. JSDom aids in establishing this environment for testing, making it necessary to install it as a development dependency alongside the testing library, which provides utilities for querying nodes similarly to user interactions, ensuring confidence in your UI code.</p>
<h2 id="heading-writing-your-first-test">Writing Your First Test</h2>
<p>Let's write a simple component for greeting a user:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// src/components/greeting.jsx</span>
<span class="hljs-keyword">import</span> PropTypes <span class="hljs-keyword">from</span> <span class="hljs-string">'prop-types'</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Greeting</span>(<span class="hljs-params">{ name }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hello, {name}!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
}

Greeting.propTypes = {
  <span class="hljs-attr">name</span>: PropTypes.string.isRequired,
}
</code></pre>
<p>Here's how you can write a test for this component using Vitest &amp; Testing Library:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// src/components/greeting.test.jsx</span>
<span class="hljs-keyword">import</span> { describe, it, expect } <span class="hljs-keyword">from</span> <span class="hljs-string">'vitest'</span>
<span class="hljs-keyword">import</span> { render, screen } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>
<span class="hljs-keyword">import</span> { Greeting } <span class="hljs-keyword">from</span> <span class="hljs-string">'./greeting'</span>

describe(<span class="hljs-string">'&lt;Greeting /&gt;'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'greets the user'</span>, <span class="hljs-function">() =&gt;</span> {
    render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Greeting</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"John"</span> /&gt;</span></span>)
    expect(screen.getByText(<span class="hljs-regexp">/John/i</span>)).toBeDefined()
  })
})
</code></pre>
<p>So, let's explain what's going on here:</p>
<ul>
<li><p>you can think of <code>describe</code> as a wrapper for your tests, it creates a context for whatever it's happening inside.</p>
</li>
<li><p><code>it</code> is an alias for <code>test</code> and it contains the expectation for what you are testing. It is composed of the name of the test and a function.</p>
</li>
<li><p><code>render</code> it's a function from Testing Library that allows rendering a React component - in this case, we passed a hard-coded name "John"</p>
</li>
<li><p><code>expect</code> it is used to create assertions - like to check if there is a text with the word "John" painted on the screen</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: Note that the test file extension ends in <code>jsx</code> This is because we are rendering a JSX component under the hood by using the <code>render</code> function from Testing Library</div>
</div>

<p>Now, you can run this test using <code>pnpm run test</code>. If everything is set up correctly, you should see a passing test in your console.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688963269924/5058b67c-f8d6-44c5-8bdd-e5bed135c473.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: Vitest by default is executed in watch mode, meaning that if you only want to run your tests once, you need to run them like <code>vitest run</code></div>
</div>

<p>Let's then update our scripts in the <code>package.json</code> file:</p>
<pre><code class="lang-json">...
<span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"vite"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"vite build"</span>,
    <span class="hljs-attr">"lint"</span>: <span class="hljs-string">"eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0"</span>,
    <span class="hljs-attr">"preview"</span>: <span class="hljs-string">"vite preview"</span>,
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"vitest run"</span>,
    <span class="hljs-attr">"test:dev"</span>: <span class="hljs-string">"vitest"</span>,
    <span class="hljs-attr">"coverage"</span>: <span class="hljs-string">"vitest run --coverage"</span>
},
...
</code></pre>
<p>Now, we have a script for just one run and another for a testing developing experience.</p>
<h2 id="heading-checking-coverage">Checking coverage</h2>
<p>If you saw in the scripts there is a third one called <code>coverage</code>, this is another great utility that provides Vitest that we are gonna be covering here. Nevertheless, right now since they have migrated from the <a target="_blank" href="https://github.com/bcoe/c8">c8</a> to <a target="_blank" href="https://v8.dev/blog/javascript-code-coverage">v8</a> coverage library, once you run the script <code>pnpm run coverage</code> you'll get this message in the terminal:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688965225874/8c069d2a-ca7d-4a9f-99d6-3079388d95e9.png" alt class="image--center mx-auto" /></p>
<p>Simply respond with "yes" and the switch will be made automatically for you. Afterward, run the script once more and you'll receive the report.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688965343371/f24ec616-5abc-4964-90ee-2e0ad74ea8ec.png" alt class="image--center mx-auto" /></p>
<p>This will generate a folder with a UI that you can open in the browser.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688966358818/39e83261-2f58-4a45-8c86-4588eee1f438.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688966383746/4afbaea4-e68b-4ed3-b978-18febe7f1d08.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-vitest-ui">Vitest UI</h2>
<p>Another amazing tool I want to share is the Vitest UI library, which allows you to view and interact with your tests. This is completely optional, and as you'll see, it needs to be installed separately, but trust me, it's worth it.</p>
<pre><code class="lang-bash">npm i -D @vitest/ui
</code></pre>
<p>Now, let's update again our <code>package.json</code> file and add <code>"test:ui": "vitest --ui"</code></p>
<pre><code class="lang-bash">...
  <span class="hljs-string">"test"</span>: <span class="hljs-string">"vitest run"</span>,
  <span class="hljs-string">"test:dev"</span>: <span class="hljs-string">"vitest"</span>,
  <span class="hljs-string">"test:ui"</span>: <span class="hljs-string">"vitest --ui"</span>,
  <span class="hljs-string">"coverage"</span>: <span class="hljs-string">"vitest run --coverage"</span>
},
...
</code></pre>
<p>that's it, if you run it, you'll get this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688965987350/3cd5a1ba-dcea-4c10-a7c9-27d4759046b9.png" alt class="image--center mx-auto" /></p>
<p>a complete playground that provides you with:</p>
<ul>
<li><p>test's code</p>
</li>
<li><p>a convenient module graph</p>
</li>
<li><p>a console to watch errors</p>
</li>
<li><p>search capacity</p>
</li>
<li><p>dark mode switch 😎</p>
</li>
</ul>
<h2 id="heading-tips-and-tricks">Tips and Tricks</h2>
<p>Here are some tips and tricks for mastering Vitest:</p>
<ol>
<li><p><strong>Use Descriptive Test Names</strong>: Descriptive test names can make it easier to understand what a test is doing and why it might be failing.</p>
</li>
<li><p><strong>Group Related Tests</strong>: You can group related tests using <code>describe</code> blocks. This can make your tests easier to read and manage.</p>
</li>
<li><p><strong>Take Advantage of Vitest's Features</strong>: Vitest comes with several features designed to make testing easier, such as parallel test execution and automatic retries for flaky tests. Be sure to take advantage of these features.</p>
</li>
<li><p><strong>Keep Your Tests Small and Focused</strong>: Each test should focus on a single piece of functionality. Smaller, more focused tests are easier to understand and debug.</p>
</li>
<li><p><strong>Use Mocks and Stubs Sparingly</strong>: While mocks and stubs can be useful, they can also make your tests more complex and harder to maintain. Use them sparingly and only when necessary.</p>
</li>
</ol>
<h2 id="heading-bonus">Bonus</h2>
<p>As usual, I’ll let you with the fully configured <a target="_blank" href="https://github.com/aiherrera/testing-vite">Github repository</a> with the example used in this article for you to check &amp; try out.</p>
<p>I plan to add more examples over time!🧑‍💻</p>
<h2 id="heading-last-thoughts">Last Thoughts</h2>
<p>In conclusion, Vite and Vitest offer a powerful combination for developing and testing modern web applications. With the right knowledge and techniques, you can create robust, reliable tests for your Vite applications. Happy testing!</p>
<p>Hope you enjoyed this article, if so, consider giving it a like 👍🏻 and Stay Awesome!</p>
]]></content:encoded></item><item><title><![CDATA[Exploring Common Design Patterns in React]]></title><description><![CDATA[Introduction
Design patterns play a crucial role in building well-structured and maintainable applications. React, being a popular JavaScript library for building user interfaces, provides developers with flexibility and freedom to choose from variou...]]></description><link>https://blog.aiherrera.com/exploring-common-design-patterns-in-react</link><guid isPermaLink="true">https://blog.aiherrera.com/exploring-common-design-patterns-in-react</guid><category><![CDATA[design patterns]]></category><category><![CDATA[React]]></category><category><![CDATA[maintainability]]></category><category><![CDATA[reusablility]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Tue, 04 Jul 2023 00:34:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1688414784848/6faf3571-8e74-4a7f-8f62-f7b65688f8b7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>Design patterns play a crucial role in building well-structured and maintainable applications. React, being a popular JavaScript library for building user interfaces, provides developers with flexibility and freedom to choose from various design patterns. In this article, we will explore some common design patterns used in React applications and understand their purposes with practical examples.</p>
<p>On a daily-basis-code-rush to get the job done, it is usual to get over these patterns or just use them without notice.</p>
<p>The purpose of this article is to give an overview of what I consider (which means this is an opinionated article 😅, there are plenty more patterns) are the most used patterns in React.</p>
<h3 id="heading-component-pattern">Component Pattern</h3>
<p>The Component Pattern is the foundation of React development, promoting reusability and modularity. It involves decomposing the UI into reusable, modular components. Components in React can be functional or class-based. They encapsulate their logic and rendering, making it easier to manage and maintain the application's UI.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Button Component</span>
<span class="hljs-keyword">const</span> Button = <span class="hljs-function">(<span class="hljs-params">{ onClick, children }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClick}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
};

<span class="hljs-comment">// App Component</span>
<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Button clicked!'</span>);
  };

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>Click Me<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span></span>;
};
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro Tip: Nowadays, using functional composition in React is highly recommended. Only in rare cases would class-based components be useful, as most of the React lifecycle methods can be applied within <code>useEffect</code> for versions 16.8 and above.</div>
</div>

<h3 id="heading-render-props">Render Props</h3>
<p>The Render Props pattern allows components to share functionality through a common interface. It involves passing a function as a prop to a component, which allows the component to render the result of that function. This pattern enables code reuse and flexibility in building components.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// MouseTracker Component</span>
<span class="hljs-keyword">const</span> MouseTracker = <span class="hljs-function">(<span class="hljs-params">{ render }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> handleMouseMove = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { clientX, clientY } = event;
    render(clientX, clientY);
  };

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onMouseMove</span>=<span class="hljs-string">{handleMouseMove}</span>&gt;</span>Move the mouse!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-comment">// MouseCoordinatesDisplay Component</span>
<span class="hljs-keyword">const</span> MouseCoordinatesDisplay = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">MouseTracker</span>
      <span class="hljs-attr">render</span>=<span class="hljs-string">{(x,</span> <span class="hljs-attr">y</span>) =&gt;</span> (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
          Mouse coordinates: {x}, {y}
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    /&gt;</span>
  );
};
</code></pre>
<h3 id="heading-containercomponent-pattern">Container/Component Pattern</h3>
<p>The Container/Component Pattern separates data logic (container components) from UI rendering (UI components). Container components handle data fetching, state management, and business logic, while UI components focus on rendering the UI based on props. This pattern promotes better separation of concerns and code maintainability.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// DataContainer Component</span>
<span class="hljs-keyword">const</span> DataContainer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [data, setData] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchData()
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> setData(response.data))
      .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(error));
  }, []);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">DataComponent</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{data}</span> /&gt;</span></span>;
};

<span class="hljs-comment">// UIComponent</span>
<span class="hljs-keyword">const</span> UIComponent = <span class="hljs-function">(<span class="hljs-params">{ data }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {data.map((item) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>{item.name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
</code></pre>
<h3 id="heading-higher-order-component-hoc-decorator-pattern">Higher-Order Component (HOC) - Decorator Pattern</h3>
<p>Higher-Order Components (HOC) are functions that take a component and return an enhanced version of that component. HOCs enable the addition of extra behavior or modification of the rendering of the wrapped component. They provide a way to share common functionality among multiple components.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// withAuthentication HOC</span>
<span class="hljs-keyword">const</span> withAuthentication = <span class="hljs-function">(<span class="hljs-params">WrappedComponent</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> isAuthenticated = <span class="hljs-literal">true</span>; <span class="hljs-comment">// Logic to determine authentication status</span>

  <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">props</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (isAuthenticated) {
      <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">WrappedComponent</span> {<span class="hljs-attr">...props</span>} /&gt;</span></span>;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Please log in to access this component.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
    }
  };
};

<span class="hljs-comment">// MyComponent</span>
<span class="hljs-keyword">const</span> MyComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Authenticated component<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> withAuthentication(MyComponent);
</code></pre>
<h3 id="heading-context-api"><strong>Context API</strong></h3>
<p>The Context API in React provides a way to share state and data across multiple components without explicitly passing props. It eliminates the need for prop drilling and simplifies the management of global or application-level state.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ThemeContext</span>
<span class="hljs-keyword">const</span> ThemeContext = createContext(<span class="hljs-string">'light'</span>);

<span class="hljs-comment">// ThemeProvider Component</span>
<span class="hljs-keyword">const</span> ThemeProvider = <span class="hljs-function">(<span class="hljs-params">{ children }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"dark"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">ThemeContext.Provider</span>&gt;</span></span>;
};

<span class="hljs-comment">// ThemeComponent Component</span>
<span class="hljs-keyword">const</span> ThemeComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> theme = useContext(ThemeContext);
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Current theme: {theme}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};
</code></pre>
<h3 id="heading-singleton-pattern"><strong>Singleton Pattern</strong></h3>
<p>The Singleton Pattern ensures that only one instance of a component or service is created and shared throughout the application. It provides global access to a single instance, preventing multiple instances from being created.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-keyword">const</span> apiClient = (<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">let</span> instance = <span class="hljs-literal">null</span>;

  <span class="hljs-keyword">const</span> createInstance = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> api = axios.create({
      <span class="hljs-attr">baseURL</span>: <span class="hljs-string">'https://api.example.com'</span>,
      <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`&lt;Your Auth Token&gt;`</span>,
      Content-Type: <span class="hljs-string">"application/json"</span>,
      <span class="hljs-attr">timeout</span> : <span class="hljs-number">1000</span>,
      <span class="hljs-attr">withCredentials</span>: <span class="hljs-literal">true</span>
    });

    <span class="hljs-keyword">return</span> api;
  };

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">getInstance</span>: <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">if</span> (!instance) {
        instance = createInstance();
      }
      <span class="hljs-keyword">return</span> instance;
    },
  };
})();

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> apiClient;
</code></pre>
<p>In this example, the <code>apiClient</code> encapsulates API functionality using <code>axios</code> and is implemented as a <code>Singleton</code>. The static <code>getInstance</code> method ensures only one instance is created and shared throughout the application. This centralized <code>API client</code> promotes code consistency and prevents resource duplication.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> apiClient <span class="hljs-keyword">from</span> <span class="hljs-string">'./apiClient'</span>;

<span class="hljs-keyword">const</span> UserList = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [users, setUsers] = useState([]);
  <span class="hljs-keyword">const</span> [newUser, setNewUser] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> fetchUsers = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> api = apiClient.getInstance();

    api.get(<span class="hljs-string">'/users'</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> setUsers(response.data))
      .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
  };

  <span class="hljs-keyword">const</span> handleAddUser = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> api = apiClient.getInstance();

    api.post(<span class="hljs-string">'/users'</span>, { <span class="hljs-attr">name</span>: newUser })
      .then(<span class="hljs-function">() =&gt;</span> {
        setNewUser(<span class="hljs-string">''</span>);
        fetchUsers();
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> <span class="hljs-built_in">console</span>.error(error));
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchUsers();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {users.map((user) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{newUser}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setNewUser(e.target.value)}
          placeholder="Enter a new user"
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleAddUser}</span>&gt;</span>Add User<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> UserList;
</code></pre>
<p>In this example, the GET and POST methods use a single instance of the axios library, ensuring resource efficiency and consistent API functionality across the application.</p>
<h3 id="heading-proxy-pattern"><strong>Proxy Pattern</strong></h3>
<p>The Proxy Pattern controls access to a component and allows for additional logic or behavior before accessing or modifying it. It acts as an intermediary between the client and the component, providing additional functionality.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> ProxyComponent = <span class="hljs-function">(<span class="hljs-params">{ valid, children }</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (valid) {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ActualComponent</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">ActualComponent</span>&gt;</span></span>;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Invalid component<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
  }
};
</code></pre>
<blockquote>
<p>You probably have had a Deja vu right now, it is quite similar to the approach used in the Higher-Order Components section right? In this case, we just isolated the Proxy pattern for demonstration purposes, but you are now starting to get the big picture!</p>
</blockquote>
<h3 id="heading-factory-pattern"><strong>Factory Pattern</strong></h3>
<p>The Factory Pattern provides a way to create instances of components or objects dynamically based on certain conditions or configurations. It encapsulates the creation logic and allows for flexible object creation.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// Factory function to create notification components</span>
<span class="hljs-keyword">const</span> createNotificationComponent = <span class="hljs-function">(<span class="hljs-params">type</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'email'</span>:
      <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">{ message }</span>) =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Email notification: {message}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">'sms'</span>:
      <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">{ message }</span>) =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>SMS notification: {message}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">'push'</span>:
      <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">{ message }</span>) =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Push notification: {message}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Unsupported notification type: <span class="hljs-subst">${type}</span>`</span>);
  }
};

<span class="hljs-comment">// NotificationFactory component</span>
<span class="hljs-keyword">const</span> NotificationFactory = <span class="hljs-function">(<span class="hljs-params">{ type, message }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> NotificationComponent = createNotificationComponent(type);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">NotificationComponent</span> <span class="hljs-attr">message</span>=<span class="hljs-string">{message}</span> /&gt;</span></span>;
};

<span class="hljs-comment">// Usage example</span>
<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">NotificationFactory</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">message</span>=<span class="hljs-string">"New email received"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">NotificationFactory</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"sms"</span> <span class="hljs-attr">message</span>=<span class="hljs-string">"New SMS received"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">NotificationFactory</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"push"</span> <span class="hljs-attr">message</span>=<span class="hljs-string">"New push notification"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h2 id="heading-memoization-pattern">Memoization Pattern</h2>
<p>The Memoization Pattern involves caching the result of a component's rendering to improve performance by preventing unnecessary re-rendering. It is useful when a component's rendering depends on expensive computations or when its props do not change frequently.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useMemo } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// Expensive Fibonacci calculation function</span>
<span class="hljs-keyword">const</span> fibonacci = <span class="hljs-function">(<span class="hljs-params">n</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (n &lt;= <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> n;
  <span class="hljs-keyword">return</span> fibonacci(n - <span class="hljs-number">1</span>) + fibonacci(n - <span class="hljs-number">2</span>);
};

<span class="hljs-comment">// FibonacciComponent</span>
<span class="hljs-keyword">const</span> FibonacciComponent = <span class="hljs-function">(<span class="hljs-params">{ n }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> memoizedFibonacci = useMemo(<span class="hljs-function">() =&gt;</span> fibonacci(n), [n]);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>The Fibonacci number at index {n} is {memoizedFibonacci}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-comment">// App</span>
<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [index, setIndex] = useState(<span class="hljs-number">10</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">FibonacciComponent</span> <span class="hljs-attr">n</span>=<span class="hljs-string">{index}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIndex(index + 1)}&gt;Increase Index<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h2 id="heading-lazy-loading-pattern"><strong>Lazy Loading Pattern</strong></h2>
<p>A lazy Loading Pattern is a design technique used in software development where the initialization or loading of resources, such as data or objects, is delayed until they are needed, improving performance and reducing the initial load time.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro Tip: In React 18, the introduction of the Suspense component, enables developers to implement the Lazy Loading Pattern, deferring resource-intensive tasks and improving performance and initial load times for a seamless user experience.</div>
</div>

<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { lazy, Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

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

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">div</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>}&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">LazyLoadedComponent</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span></span>
  );
};
</code></pre>
<h2 id="heading-observer-pattern">Observer Pattern</h2>
<p>The Observer Pattern in React is a design pattern that allows an object (called the subject) to maintain a list of its dependents (called observers) and automatically notify them of any state changes, enabling a seamless user experience.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// ChatService</span>
<span class="hljs-keyword">const</span> ChatService = {
  <span class="hljs-attr">listeners</span>: [],
  notify(message) {
    <span class="hljs-built_in">this</span>.listeners.forEach(<span class="hljs-function">(<span class="hljs-params">listener</span>) =&gt;</span> listener(message));
  },
  subscribe(listener) {
    <span class="hljs-built_in">this</span>.listeners.push(listener);
  },
  unsubscribe(listener) {
    <span class="hljs-built_in">this</span>.listeners = <span class="hljs-built_in">this</span>.listeners.filter(<span class="hljs-function">(<span class="hljs-params">l</span>) =&gt;</span> l !== listener);
  },
};

<span class="hljs-comment">// ChatRoom component</span>
<span class="hljs-keyword">const</span> ChatRoom = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [messages, setMessages] = useState([]);
  <span class="hljs-keyword">const</span> [newMessage, setNewMessage] = useState(<span class="hljs-string">''</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> handleNewMessage = <span class="hljs-function">(<span class="hljs-params">message</span>) =&gt;</span> {
      setMessages(<span class="hljs-function">(<span class="hljs-params">prevMessages</span>) =&gt;</span> [...prevMessages, message]);
    };

    ChatService.subscribe(handleNewMessage);

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      ChatService.unsubscribe(handleNewMessage);
    };
  }, []);

  <span class="hljs-keyword">const</span> handleSendMessage = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> message = { <span class="hljs-attr">text</span>: newMessage, <span class="hljs-attr">timestamp</span>: <span class="hljs-built_in">Date</span>.now() };
    ChatService.notify(message);
    setNewMessage(<span class="hljs-string">''</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {messages.map((message, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>{message.text}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{newMessage}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setNewMessage(e.target.value)}
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSendMessage}</span>&gt;</span>Send<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-comment">// Notification component</span>
<span class="hljs-keyword">const</span> Notification = <span class="hljs-function">(<span class="hljs-params">{ message }</span>) =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`New message: <span class="hljs-subst">${message.text}</span>`</span>);
  }, [message]);

  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
};

<span class="hljs-comment">// App component</span>
<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ChatRoom</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Notification</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here is a complete functional example of this pattern for better understanding. Feel free to check it out - just type any message and hit enter, it should update both the Notification and Message panel components at the same time, since they are both subscribed and listening for changes 🕵️‍♂️</p>
<iframe src="https://stackblitz.com/edit/react-observer-pattern-example?ctl=1&amp;embed=1&amp;hideExplorer=1&amp;hideNavigation=1&amp;view=preview" width="800" height="650"></iframe>

<h2 id="heading-error-boundary-pattern">Error Boundary Pattern</h2>
<p>Error Boundary Pattern is a design pattern in React used to catch and handle errors in components, preventing the entire application from crashing and displaying a fallback UI when an error occurs.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// ErrorBoundary component</span>
<span class="hljs-keyword">const</span> ErrorBoundary = <span class="hljs-function">(<span class="hljs-params">{ children }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [hasError, setHasError] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> handleOnError = <span class="hljs-function">() =&gt;</span> {
    setHasError(<span class="hljs-literal">true</span>);
  };

  <span class="hljs-keyword">if</span> (hasError) {
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Oops! Something went wrong.<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
  }

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onError</span>=<span class="hljs-string">{handleOnError}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-comment">// ErrorProneComponent</span>
<span class="hljs-keyword">const</span> ErrorProneComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Simulating an error</span>
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Error occurred in ErrorProneComponent'</span>);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>ErrorProneComponent<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-comment">// App component</span>
<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ErrorBoundary</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ErrorProneComponent</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ErrorBoundary</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro Tip: This pattern is built into the Next.js framework to catch boundary errors and prevent the entire UI from breaking.</div>
</div>

<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>In this article, we explored some common design patterns used in React applications.</p>
<p>These design patterns, such as the Component Pattern, Render Props, Container/Component Pattern, Higher-Order Components (HOC), Context API, and more, provide developers with strategies and best practices for building robust and scalable React applications. Understanding and effectively applying these design patterns can significantly improve code organization, reusability, and maintainability.</p>
<p>Remember, the choice of design pattern depends on the specific requirements and structure of your application. Experiment with these patterns and choose the ones that best suit your needs. Happy coding!</p>
<p>Hope you enjoyed this article, if so, consider giving it a like 👍🏻 and Stay Awesome!</p>
]]></content:encoded></item><item><title><![CDATA[Building My Own Visual Studio Code Extension Bundle]]></title><description><![CDATA[Introduction
Recently we were struggling at work with newcomers joining our team and setting out each fresh equipment with all the required development environment. And from all the things we are trying to automate, I thought it would be nice to stre...]]></description><link>https://blog.aiherrera.com/building-my-own-visual-studio-code-extension-bundle</link><guid isPermaLink="true">https://blog.aiherrera.com/building-my-own-visual-studio-code-extension-bundle</guid><category><![CDATA[vscode extensions]]></category><category><![CDATA[marketplace]]></category><category><![CDATA[vscode extension pack]]></category><category><![CDATA[vscode settings]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Sun, 25 Jun 2023 01:55:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1687596053119/b8e343cd-00bb-482d-ac40-ccf8bfd864e2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Recently we were struggling at work with newcomers joining our team and setting out each fresh equipment with all the required development environment. And from all the things we are trying to automate, I thought it would be nice to streamline the process of installing all the required &amp; recommended VSCode (which is the code editor we use - most of us I think 🙊) extensions for the project.</p>
<p>So, I create this VSCode extension pack for three reasons:</p>
<ol>
<li><p>Learn the whole process of how to create a VSCode extension throughout the Azure DevOps portal to Marketplace</p>
</li>
<li><p>Have a handy set of extensions for any new computer I have to grab and prepare the workspace from scratch</p>
</li>
<li><p>Sharing. Yes! - sharing with the community 👥</p>
</li>
</ol>
<p>This article shares my experience creating a VSCode extension pack. I'll be showing you step-by-step the details of my journey. Also, I'll be sharing how I have configured my settings.json file and why.</p>
<h2 id="heading-setting-the-stage">Setting the Stage</h2>
<p>The first thing to create, to build an extension, is a project. Well, there is a tool that have us covered with a boilerplate to not start from zero: <a target="_blank" href="https://yeoman.io/learning/">Yeoman</a>.</p>
<p>As they state on their website:</p>
<blockquote>
<p>Yeoman is a generic scaffolding system allowing the creation of any kind of app. It allows for rapidly getting started on new projects and streamlines the maintenance of existing projects.</p>
</blockquote>
<p>This is an amazing tool that I'll be covering in a later post(to show how to scaffold &amp; ship your own CLI), but getting back to our journey, the Microsoft team built an <a target="_blank" href="https://www.npmjs.com/package/generator-code">npm package</a> (a project generator using Yeoman) that helps the process a lot.<br />So, the first step is gonna install these two packages globally with this command:</p>
<pre><code class="lang-bash">npm install -g yo generator-code
</code></pre>
<p>After that, you are ready to go. Run `yo code` as shown in the image below and you'll see a bunch of possible options, select: New Extension Pack</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687597674808/eb1da58f-ebac-4ffe-b556-4523288a9507.png" alt class="image--center mx-auto" /></p>
<p>The CLI is gonna ask some questions, just fill out them accordingly:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687643737577/9ac3fa65-bfdb-4564-a36f-6f00e83a2de0.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: The second question asks about pulling the current extensions you have installed in your VSCode, I said yes because I already had the extensions I wanted to include in my package. Nevertheless, you can modify this later on or just say no and add them afterward.</div>
</div>

<p>That's it! You'll get a folder structure like this one:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687643826604/909c14a4-6094-4074-8940-ab341415340d.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-building-the-extension-bundle">Building the Extension Bundle</h2>
<p>Now it is time to start creating the extension bundle. If you selected yes to the question of pulling the currently installed extension in the VSCode editor, you have 50% of the work done, the rest is configuration. Let's dive in.</p>
<p>If you open your <code>package.json</code> file it would look like this:</p>
<pre><code class="lang-bash">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"my-first-extension"</span>,
  <span class="hljs-string">"displayName"</span>: <span class="hljs-string">"my-first-extension"</span>,
  <span class="hljs-string">"description"</span>: <span class="hljs-string">"This is my first extension"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"0.0.1"</span>,
  <span class="hljs-string">"engines"</span>: {
    <span class="hljs-string">"vscode"</span>: <span class="hljs-string">"^1.79.0"</span>
  },
  <span class="hljs-string">"categories"</span>: [
    <span class="hljs-string">"Extension Packs"</span>
  ],
  <span class="hljs-string">"extensionPack"</span>: [
    <span class="hljs-string">"adpyke.codesnap"</span>,
    <span class="hljs-string">"bradlc.vscode-tailwindcss"</span>,
    <span class="hljs-string">"ChakrounAnas.turbo-console-log"</span>,
    <span class="hljs-string">"christian-kohler.npm-intellisense"</span>,
    <span class="hljs-string">"christian-kohler.path-intellisense"</span>,
    <span class="hljs-string">"dbaeumer.vscode-eslint"</span>,
....
}
</code></pre>
<p>Let's break this down:</p>
<ul>
<li><p>The first properties: name, displayName, description and version, are related to the extension you want to create.</p>
</li>
<li><p>The engine's property is related to what versions of VSCode can support your extension.</p>
</li>
<li><p>The categories list where your extension would be available in the Marketplace.</p>
</li>
<li><p>And the extensionPack is where the currently installed extensions are pre-populated.</p>
</li>
</ul>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: You can know which extensions you have installed in your VSCode by running this command: <code>code --list-extensions</code> and, to filter them if you have a profile set: <code>code --profile Frontend --list-extensions</code></div>
</div>

<p>After this, I added some other configurations to my <code>package.json</code></p>
<ul>
<li><p>preview: this is set to false because my extension isn't in preview mode, it is ready to use. If you are developing a new extension this may be useful to tell the users this is in development and can be unstable.</p>
</li>
<li><p>publisher: the name you are gonna use to author your extension</p>
</li>
<li><p>icon: the image it is gonna appear in the Marketplace (it has to be 128x128px or 256x256px for retina display)</p>
</li>
<li><p>repository: well this has to be more with the repository where I host the project, this case Github.</p>
</li>
</ul>
<pre><code class="lang-bash">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"my-first-extension"</span>,
  <span class="hljs-string">"displayName"</span>: <span class="hljs-string">"my-first-extension"</span>,
  <span class="hljs-string">"description"</span>: <span class="hljs-string">"This is my first extension"</span>,
- <span class="hljs-string">"version"</span>: <span class="hljs-string">"0.0.1"</span>,
+ <span class="hljs-string">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
+ <span class="hljs-string">"preview"</span>: <span class="hljs-literal">false</span>,
+ <span class="hljs-string">"publisher"</span>: <span class="hljs-string">"aiherrera"</span>,
+ <span class="hljs-string">"icon"</span>: <span class="hljs-string">"icon.png"</span>,
+ <span class="hljs-string">"repository"</span>: {
+   <span class="hljs-string">"type"</span>: <span class="hljs-string">"git"</span>,
+   <span class="hljs-string">"url"</span>: <span class="hljs-string">"https://github.com/aiherrera/vscode-extension-package.git"</span>
+ },
  <span class="hljs-string">"engines"</span>: {
    <span class="hljs-string">"vscode"</span>: <span class="hljs-string">"^1.79.0"</span>
  },
  <span class="hljs-string">"categories"</span>: [
    <span class="hljs-string">"Extension Packs"</span>
  ],
  <span class="hljs-string">"extensionPack"</span>: [
    <span class="hljs-string">"adpyke.codesnap"</span>,
    <span class="hljs-string">"bradlc.vscode-tailwindcss"</span>,
    <span class="hljs-string">"ChakrounAnas.turbo-console-log"</span>,
    <span class="hljs-string">"christian-kohler.npm-intellisense"</span>,
    <span class="hljs-string">"christian-kohler.path-intellisense"</span>,
    <span class="hljs-string">"dbaeumer.vscode-eslint"</span>,
....
}
</code></pre>
<p>To finish this section let's concentrate on the repository part.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: I strongly recommend installing the <a target="_blank" href="https://www.npmjs.com/package/cgx">cgx library</a> from <a target="_blank" href="https://github.com/jeroenouw">jeroenouw</a>. This library is a CLI to Generate recommended documentation/files to improve contribution.</div>
</div>

<p>So, let's do it!</p>
<pre><code class="lang-bash">npm i -g cgx
</code></pre>
<p>With that in place now you just call it in any terminal, here are some screenshots about the steps:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687649819350/b17d35f5-1110-4772-bb28-7e8cb80b510d.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687649847165/953f40fa-0c2d-4e4c-a421-66a82741977f.png" alt class="image--center mx-auto" /></p>
<p>What I did here was to first generate all the recommended files and after that add the ones that I thought I would match with my interests.</p>
<blockquote>
<p>Note here that most of the generated files won't need any modification, but others may need some refinement, yet most of the work is already done. I loved this repository, so if you do, starred it, to give support to community members.</p>
</blockquote>
<h2 id="heading-creating-an-azure-devops-organization">Creating an Azure DevOps Organization</h2>
<p>The next step to get to publish your extension is to <a target="_blank" href="https://learn.microsoft.com/azure/devops/organizations/accounts/create-organization">create an Azure DevOps Organization</a>, which is a streamlined process.</p>
<p>Once you have created your organization, you need to set up a Personal Access Token:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687650529361/7260948b-1d6d-4750-bf53-3c21be56967d.png" alt class="image--center mx-auto" /></p>
<p>Here are the instructions:</p>
<ul>
<li><p>Create a meaningful name for your token</p>
</li>
<li><p>Select the name of the just-created organization</p>
</li>
<li><p>Add an expiration time</p>
</li>
<li><p>At the bottom of the scopes click on Show more scopes, it would expand all the possible scopes, scroll down until you find Marketplace and select Manage</p>
</li>
<li><p>Click Create</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687650631243/e3e9d824-7440-414e-ab39-4326223a5c4d.png" alt class="image--center mx-auto" /></p>
<p>The last step is to <a target="_blank" href="https://marketplace.visualstudio.com/manage/publishers">create a publisher</a>, this is an identity that allows you to publish extensions in the Visual Studio Code Marketplace.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: The most important fields here are the Name and the ID. The name has to match the one you set in your package.json as a publisher and the ID is a unique name that identifies your extension in the Marketplace, so, you have to check name availability.</div>
</div>

<h2 id="heading-publishing-the-extension-package">Publishing the extension package</h2>
<p>Now we are ready to publish our Extension Pack. For this, we are gonna log in using our publisher name:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># publisher name</span>
npx @vscode/vsce login aiherrera
<span class="hljs-comment"># copy/paste the Personal Access Token you created at the begining</span>
https://marketplace.visualstudio.com/manage/publishers/
Personal Access Token <span class="hljs-keyword">for</span> publisher <span class="hljs-string">'aiherrera'</span>: **********************
<span class="hljs-comment"># if everything is ok, your are gonna get a succeeded message</span>
The Personal Access Token verification succeeded <span class="hljs-keyword">for</span> the publisher <span class="hljs-string">'aiherrera'</span>.
</code></pre>
<p>Once we are logged in, we are ready to create or first publication of our Extension Pack:</p>
<pre><code class="lang-bash">npx @vscode/vsce publish
 INFO  Publishing <span class="hljs-string">'aiherrera.my-first-extension v1.0.0'</span>...
 INFO  Extension URL (might take a few minutes): https://marketplace.visualstudio.com/items?itemName=aiherrera.my-first-extension
 INFO  Hub URL: https://marketplace.visualstudio.com/manage/publishers/aiherrera/extensions/my-first-extension/hub
 DONE  Published aiherrera.my-first-extension v1.0.0.
</code></pre>
<p>✨ Congrats, you have published your first extension ✨</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Pro tip: Now, every time you update your extension, you have to update the version number in your <code>package.json</code> let's say we just publish <code>v1.0.0</code>, and you add a new extension to the package, update the version to <code>v1.0.1</code> and good to go.</div>
</div>

<h2 id="heading-exploring-settingsjson">Exploring settings.json</h2>
<p>After creating the extension, I looked into my VSCode settings: the settings.json file. This file helps customize the editor in many ways. I checked the default settings and compared them to what I needed. Then, I changed important settings like indentation, theme, font, and code formatting to make it look and work how I wanted.</p>
<p>I created a <a target="_blank" href="https://gist.github.com/aiherrera/04c133dd0343490601010d3cb0b2a30c">Github gist</a> with the configurations I use in most of my projects.</p>
<blockquote>
<p>Take into account that certain configurations depend expressly on some extensions that live in the Extension Pack I created.</p>
</blockquote>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="04c133dd0343490601010d3cb0b2a30c"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/aiherrera/04c133dd0343490601010d3cb0b2a30c" class="embed-card">https://gist.github.com/aiherrera/04c133dd0343490601010d3cb0b2a30c</a></div><p> </p>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<ul>
<li><p>I learned how to create my own Visual Studio Code extension pack from generating the project to publishing the extension in the Marketplace</p>
</li>
<li><p>On the journey, I learned some nice tools that I will use, for sure, in other projects</p>
</li>
<li><p>This will help my newcomer teammates to streamline the process of setting up their environments</p>
</li>
</ul>
<p>Hope you enjoyed this article, if so, consider giving it a like and a <a target="_blank" href="https://github.com/aiherrera/vscode-extension-package/stargazers">star the project</a> on Github.</p>
<p>Here is the created <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=aiherrera.vscode-extension-package">extension</a> on the VSCode Marketplace.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687659509291/ba735338-abb0-43f5-866e-105e290bef11.png" alt class="image--center mx-auto" /></p>
<p>Stay tunned &amp; happy coding!</p>
<p><img src="https://is5-ssl.mzstatic.com/image/thumb/EdwF2n5WFoJMS1BUsKSmkQ/1200x675mf.jpg" alt="Kung Fu Panda 3 | Apple TV (MX)" /></p>
]]></content:encoded></item><item><title><![CDATA[Fast Database Diagrams with QuickDBD: An Easy-to-Use Tool]]></title><description><![CDATA[Introduction
When it comes to designing and managing database schemas, QuickDBD (Quick Database Diagrams) stands out as a powerful and efficient tool. It's a free online browser-based diagramming tool that comes with a host of beneficial features. In...]]></description><link>https://blog.aiherrera.com/fast-database-diagrams-with-quickdbd-an-easy-to-use-tool</link><guid isPermaLink="true">https://blog.aiherrera.com/fast-database-diagrams-with-quickdbd-an-easy-to-use-tool</guid><category><![CDATA[Databases]]></category><category><![CDATA[UML]]></category><category><![CDATA[quickdbd]]></category><category><![CDATA[diagraming]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Tue, 06 Jun 2023 22:22:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1686089994111/af456f31-a04e-4ac8-93e2-e3f45692b7c2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>When it comes to designing and managing database schemas, QuickDBD (Quick Database Diagrams) stands out as a powerful and efficient tool. It's a free online browser-based diagramming tool that comes with a host of beneficial features. In this blog post, we'll discover what I consider the most relevant key features of QuickDBD.</p>
<p><strong>TL;DR</strong></p>
<ul>
<li><p><strong>Efficient Diagramming</strong>: This allows you to draw database diagrams by simply typing the schema, making the process quick and efficient.</p>
</li>
<li><p><strong>Professional Appearance</strong>: Creates neat and professional-looking diagrams that enhance the visual appeal of your documents and presentations.</p>
</li>
<li><p><strong>Real-Time Collaboration</strong>: Supports multi-user collaboration, allowing multiple users to edit a single diagram simultaneously.</p>
</li>
<li><p><strong>Easy Import and Export</strong>: Provides the ability to easily import and export your work. Supports exporting diagrams as images, SQL, PDF, or RTF files.</p>
</li>
<li><p><strong>Private Diagrams</strong>: The Pro plan allows you to create private diagrams that are not visible to others.</p>
</li>
<li><p><strong>Flexible Pricing</strong>: Offers a free basic plan with the option to upgrade to a Pro plan for additional features and capabilities.</p>
</li>
<li><p><strong>Browser-Based</strong>: As an online tool, QuickDBD can be used on any device with a web browser, without the need for any software installation.</p>
</li>
<li><p><strong>Templates</strong>: Provides templates to assist in creating diagrams, making the process even easier for beginners.</p>
</li>
<li><p><strong>Drag and Drop</strong>: The drag and drop feature allows even inexperienced individuals to create diagrams with ease 👌</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686088058002/f0d8cdac-8337-4ce4-8dbf-46d441a0893a.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-work-fluently-with-quickdbd"><strong>Work fluently with QuickDBD</strong></h2>
<p>One of the standout features of QuickDBD is its ability to draw schemas without leaving the keyboard. This feature allows you to work fluently and capture your ideas quickly without the interruption of GUI tools. You only need to provide the details you want, saving you time and increasing your productivity.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686088291036/8a31d0a1-6d25-4e15-a87a-9652f5ade498.png" alt class="image--center mx-auto" /></p>
<p>QuickDBD helps you create professional-looking diagrams that not only make your documents look good but also help you communicate your ideas. The tool's ability to create neat and visually appealing diagrams makes it an excellent choice for professionals who need to present their database designs to clients or team members.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686088591493/6ab14fad-7b73-42fe-9943-714cba48e820.png" alt class="image--center mx-auto" /></p>
<p>It supports real-time collaboration, allowing multiple users to edit a single diagram simultaneously. This feature is particularly useful for teams working on a shared project, as it enables everyone to contribute their ideas and see the changes made by others in real time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686088652613/08db4eab-d411-4f8b-81cf-70b13bd7941d.png" alt class="image--center mx-auto" /></p>
<p>You can easily import and export your work. This is amazing: it supports exporting into major SQL platforms like MySQL/MariaDB, Oracle, PostgreSQl, etc.</p>
<p>But, if that isn't enough, the tool supports exporting diagrams as images (PNG and SVG), PDF or RTF files, giving you the flexibility to use your diagrams in various ways. Whether you need to include a diagram in a report or use it in a presentation, QuickDBD has got you covered.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1686088711341/6f3f4f83-e76e-4e4a-8861-60d5212d6662.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-pricing">Pricing</h2>
<p>Ok, but what about pricing, are all these features for free?</p>
<p>Well yes and no, QuickDBD offers a free basic plan that allows you to create up to 10 tables and one single diagram, that's the limitation, all the other cool stuff is included as in the PRO plan.</p>
<p>The cool thing is that they are giving away free PRO licenses in exchange for publicity!</p>
<p>You can get up to 1 year of free use with PRO 🤯 <a target="_blank" href="https://app.quickdatabasediagrams.com/#/subscribe">Check it out!</a></p>
<h2 id="heading-final-thoughts"><strong>Final thoughts</strong></h2>
<p>QuickDBD is a versatile tool that makes database diagramming quick and easy. Its intuitive interface, collaborative features, and flexible export options make it a valuable asset for anyone involved in database design or management. Whether you're a database professional or a student learning about databases, QuickDBD can help you create clear and professional diagrams with ease.</p>
]]></content:encoded></item><item><title><![CDATA[Crafting Time: Building an Analog Clock with React and Tailwind CSS]]></title><description><![CDATA[Introduction
In the dynamic world of JavaScript frameworks, few hold their ground as solidly as React. Combine it with the elegance and simplicity of Tailwind CSS, and you've got a potent mix that is ideal for building user interfaces. In today's pos...]]></description><link>https://blog.aiherrera.com/crafting-time-building-an-analog-clock-with-react-and-tailwind-css</link><guid isPermaLink="true">https://blog.aiherrera.com/crafting-time-building-an-analog-clock-with-react-and-tailwind-css</guid><category><![CDATA[React]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[AnalogClock]]></category><category><![CDATA[custom-hooks]]></category><category><![CDATA[theming]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Sat, 20 May 2023 06:25:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1684288045889/d9ab9b2e-265e-4400-9aed-2050da83c54e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In the dynamic world of JavaScript frameworks, few hold their ground as solidly as React. Combine it with the elegance and simplicity of Tailwind CSS, and you've got a potent mix that is ideal for building user interfaces. In today's post, we're going to demonstrate just how powerful this combination can be.</p>
<p>At the heart of our clock will be React Hooks, a groundbreaking feature that lets us tap into React's capabilities like state and life-cycle methods without needing to write a class. Using hooks, we'll demonstrate how you can manage state and side effects more intuitively and simply, making our code cleaner and easier to understand.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684554513213/6389a553-b656-45ee-a1d2-1e4f827f91dc.png" alt="Analog clock architecture" class="image--center mx-auto" /></p>
<p>Get ready to tick-tock your way to the completion of this exciting project, as we delve into the hands-on and rewarding process of creating a React-based analog clock. Tune in as we crank up the gears and set the hands of our coding journey in motion. Let's dive into the world of React, Tailwind CSS, and Hooks, shall we?</p>
<blockquote>
<p>In my previous <a target="_blank" href="https://blog.aiherrera.com/vite-based-starter-kit-for-react-apps-without-using-frameworks">post</a>, I shared a <a target="_blank" href="https://github.com/aiherrera/vite-react-starter-template.git">template</a> for rapidly developing proof-of-concept projects. Today, we'll be utilizing it for this particular endeavor. If you haven't checked it out yet, I highly recommend doing so!</p>
</blockquote>
<p>This is what we are gonna be building.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684469845965/8c06eb80-2872-4186-930d-0b322ef4d1ec.gif" alt="Gif demonstration of the final product" class="image--center mx-auto" /></p>
<p>So, without further ado, let's embark on this exciting journey to create our very own customizable Analog Clock component in React!</p>
<h2 id="heading-setting-up-the-environment">Setting up the environment</h2>
<p>First, let's clone the template (since it is a template you can also directly create a new project in Github by clicking in the <code>Use this template</code> button):</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/aiherrera/vite-react-starter-template.git

<span class="hljs-comment"># then enter in the new generated folder</span>
<span class="hljs-built_in">cd</span> vite-react-starter-template

<span class="hljs-comment"># and open it with your favourite code editor, I use vscode ;)</span>
code .
</code></pre>
<h2 id="heading-hooks">Hooks</h2>
<p>We are gonna extract some logic into custom <a target="_blank" href="https://react.dev/learn/reusing-logic-with-custom-hooks">hooks</a> to encapsulate different reusable functionalities specific to our application requirements. These are them:</p>
<ul>
<li><p><strong>use-audio.ts</strong> - loads the audio URL for the clock ticking</p>
</li>
<li><p><strong>use-clock.ts</strong> - handles all the clock mechanisms</p>
</li>
<li><p><strong>use-device-type.ts</strong> - detects the device type based on the sizing</p>
</li>
<li><p><strong>use-size.ts</strong> - used for handling the three clock sizes</p>
</li>
<li><p><strong>use-theme.ts</strong> - handles the three theme examples (you can add your own... 😉 )</p>
</li>
</ul>
<h2 id="heading-creating-the-clock-component">Creating the clock component</h2>
<p>After that, we're going to create a new file called <code>analog-clock.tsx</code> and start to add some code to it.</p>
<p>This is pretty much the first part of it, let's break it down:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">import</span> AnalogClockActions <span class="hljs-keyword">from</span> <span class="hljs-string">'./clock-actions'</span>
<span class="hljs-keyword">import</span> { ClockSizes } <span class="hljs-keyword">from</span> <span class="hljs-string">'../../types/clock-sizes'</span>
<span class="hljs-keyword">import</span> useClock <span class="hljs-keyword">from</span> <span class="hljs-string">'../../hooks/use-clock'</span>
<span class="hljs-keyword">import</span> useTheme <span class="hljs-keyword">from</span> <span class="hljs-string">'../../hooks/use-theme'</span>
<span class="hljs-keyword">import</span> useSize <span class="hljs-keyword">from</span> <span class="hljs-string">'../../hooks/use-size'</span>
<span class="hljs-keyword">import</span> DaylightIcon <span class="hljs-keyword">from</span> <span class="hljs-string">'./daylight-icon'</span>

interface AnalogClockProps {
  defaultSize?: ClockSizes
  defaultTheme?: string
}

<span class="hljs-keyword">const</span> AnalogClock: FC&lt;AnalogClockProps&gt; = <span class="hljs-function">(<span class="hljs-params">{
  defaultSize = <span class="hljs-string">'medium'</span>,
  defaultTheme = <span class="hljs-string">'neutral'</span>,
}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [timing, isDaytime] = useClock()
  <span class="hljs-keyword">const</span> [theme, updateTheme] = useTheme(defaultTheme)
  <span class="hljs-keyword">const</span> [size, lastSize, updateSize] = useSize(defaultSize)

  <span class="hljs-keyword">const</span> clockNumbers = <span class="hljs-built_in">Array</span>.from({ <span class="hljs-attr">length</span>: <span class="hljs-number">12</span> }, <span class="hljs-function">(<span class="hljs-params">_, i</span>) =&gt;</span> i + <span class="hljs-number">1</span>)

  <span class="hljs-keyword">return</span> (
...
</code></pre>
<ul>
<li><p>Here, we are importing all the necessary components and hooks that we've separated to streamline different logic and make some of them reusable.</p>
</li>
<li><p>We've added an interface for our component with two default values for the sizing and theming of the component respectively.</p>
</li>
<li><p>The <code>clockNumbers</code> receives a generated array with the clock numbers.</p>
</li>
<li><p>Our <code>.tsx</code> begins with a component called <code>AnalogClockActions</code> which will, as you may guess, hold the actions that we are gonna apply over the clock (sizing, ticking, theming...) Here we pass two functions for our hooks that updates the current theme and size of the clock and as a default the last known size if any.</p>
</li>
</ul>
<pre><code class="lang-javascript">...
&lt;div className=<span class="hljs-string">"flex w-full cursor-pointer flex-wrap items-center justify-center gap-x-40 gap-y-0"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AnalogClockActions</span>
    <span class="hljs-attr">updateTheme</span>=<span class="hljs-string">{updateTheme}</span>
    <span class="hljs-attr">updateSize</span>=<span class="hljs-string">{updateSize}</span>
    <span class="hljs-attr">defaultSize</span>=<span class="hljs-string">{lastSize}</span>
  /&gt;</span></span>
...
</code></pre>
<p>This component renders this side of the app:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684538597340/2efdd219-7581-4632-977e-f42bef92954b.png" alt="Component actions" class="image--center mx-auto" /></p>
<ul>
<li>Then we added an Icon that is going to display a moon or a sun depending on your timezone (this is handled via <code>useClock</code> hook)</li>
</ul>
<pre><code class="lang-javascript">...
&lt;div className=<span class="hljs-string">"group relative flex cursor-pointer items-center justify-center text-sm"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">DaylightIcon</span> <span class="hljs-attr">isDaytime</span>=<span class="hljs-string">{isDaytime}</span> <span class="hljs-attr">lastSize</span>=<span class="hljs-string">{lastSize}</span> /&gt;</span></span>
...
</code></pre>
<ul>
<li>After that let's display our clock. Here we loop over our defined twelve hours and draw it inside a circle.</li>
</ul>
<pre><code class="lang-javascript">...
&lt;div className={<span class="hljs-string">`<span class="hljs-subst">${size?.dimension}</span> <span class="hljs-subst">${theme?.main}</span> <span class="hljs-subst">${theme?.shadow}</span> relative flex items-center justify-center rounded-full`</span>}&gt;
  {clockNumbers.map(<span class="hljs-function">(<span class="hljs-params">num</span>) =&gt;</span> (
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span>
       <span class="hljs-attr">key</span>=<span class="hljs-string">{num}</span>
       <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">absolute</span> ${<span class="hljs-attr">size</span>?<span class="hljs-attr">.numbers</span>} <span class="hljs-attr">text-center</span>`}
       <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">transform:</span> `<span class="hljs-attr">rotate</span>(<span class="hljs-attr">calc</span>(${<span class="hljs-attr">num</span>}*(<span class="hljs-attr">360deg</span>/<span class="hljs-attr">12</span>)))` }}&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">span</span> 
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">inline-block</span>`} 
            <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">transform:</span> `<span class="hljs-attr">rotate</span>(<span class="hljs-attr">calc</span>(${<span class="hljs-attr">num</span>}*(<span class="hljs-attr">-360deg</span>/<span class="hljs-attr">12</span>)))` }}
         &gt;</span>
           {num}
         <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>
   ))}
...
</code></pre>
<p>You'll see there are some variables in the styles, they are defined in an individual file to make it reusable:</p>
<pre><code class="lang-javascript">...
const AVALIABLE_SIZES = [
  {
    <span class="hljs-attr">key</span>: <span class="hljs-string">'large'</span>,
    <span class="hljs-attr">value</span>: {
      <span class="hljs-attr">daylight</span>: <span class="hljs-string">'h-10 w-10 right-12 -top-0 group-hover:-top-6'</span>,
      <span class="hljs-attr">dimension</span>: <span class="hljs-string">'w-96 h-96'</span>,
      <span class="hljs-attr">numbers</span>: <span class="hljs-string">'inset-5 text-5xl'</span>,
      <span class="hljs-attr">center</span>: <span class="hljs-string">'h-4 w-4 -bottom-[3px]'</span>,
      <span class="hljs-attr">hands</span>: {
        <span class="hljs-attr">hour</span>: <span class="hljs-string">'h-[6.5em] w-1.5'</span>,
        <span class="hljs-attr">minute</span>: <span class="hljs-string">'h-[11em] w-1'</span>,
        <span class="hljs-attr">second</span>: <span class="hljs-string">'h-[11em] w-[0.09em]'</span>,
      },
    },
  },
...
</code></pre>
<p>The same goes for the themes:</p>
<pre><code class="lang-javascript">...
const AVALIABLE_THEMES = [
  {
    <span class="hljs-attr">key</span>: <span class="hljs-string">'dark'</span>,
    <span class="hljs-attr">value</span>: {
      <span class="hljs-attr">main</span>: <span class="hljs-string">'bg-slate-900 text-slate-300'</span>,
      <span class="hljs-attr">shadow</span>: <span class="hljs-string">'shadow-xl shadow-slate-400'</span>,
      <span class="hljs-attr">hand</span>: {
        <span class="hljs-attr">center</span>: <span class="hljs-string">'bg-slate-200 before:bg-slate-800'</span>,
        <span class="hljs-attr">second</span>: <span class="hljs-string">'bg-slate-300'</span>,
        <span class="hljs-attr">minute</span>: <span class="hljs-string">'bg-slate-300'</span>,
        <span class="hljs-attr">hour</span>: <span class="hljs-string">'bg-slate-300'</span>,
      },
    },
  },
...
</code></pre>
<ul>
<li>And finally, we are adding a section for the clock center and hands (seconds, minutes &amp; hours)</li>
</ul>
<pre><code class="lang-xml">...
<span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); absolute z-50 flex h-4 w-4 justify-center"</span>&gt;</span>
  {/* Clock center */}
  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">size</span>?<span class="hljs-attr">.center</span>} ${<span class="hljs-attr">theme</span>?<span class="hljs-attr">.hand.center</span>} <span class="hljs-attr">absolute</span> <span class="hljs-attr">z-50</span> <span class="hljs-attr">flex</span> <span class="hljs-attr">rounded-full</span> <span class="hljs-attr">before:absolute</span> <span class="hljs-attr">before:left-0.5</span> <span class="hljs-attr">before:top-0.5</span> <span class="hljs-attr">before:h-3</span> <span class="hljs-attr">before:w-3</span> <span class="hljs-attr">before:justify-center</span> <span class="hljs-attr">before:rounded-full</span>`}&gt;</span>         
  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  {/* Second hand */}
  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">size</span>?<span class="hljs-attr">.hands</span>?<span class="hljs-attr">.second</span>} ${<span class="hljs-attr">theme</span>?<span class="hljs-attr">.hand.second</span>} <span class="hljs-attr">absolute</span> <span class="hljs-attr">bottom-1.5</span> <span class="hljs-attr">z-30</span> <span class="hljs-attr">w-1</span> <span class="hljs-attr">origin-bottom</span> <span class="hljs-attr">rounded-md</span>`} <span class="hljs-attr">style</span>=<span class="hljs-string">{timing.updateSeconds}</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  {/* Minute hand */}
  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">size</span>?<span class="hljs-attr">.hands</span>?<span class="hljs-attr">.minute</span>} ${<span class="hljs-attr">theme</span>?<span class="hljs-attr">.hand.minute</span>} <span class="hljs-attr">absolute</span> <span class="hljs-attr">bottom-1.5</span> <span class="hljs-attr">z-20</span> <span class="hljs-attr">origin-bottom</span> <span class="hljs-attr">rounded-md</span>`}               <span class="hljs-attr">style</span>=<span class="hljs-string">{timing.updateMinutes}</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  {/* Hour hand */}
  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">size</span>?<span class="hljs-attr">.hands</span>?<span class="hljs-attr">.hour</span>} ${<span class="hljs-attr">theme</span>?<span class="hljs-attr">.hand.hour</span>} <span class="hljs-attr">absolute</span> <span class="hljs-attr">bottom-1.5</span> <span class="hljs-attr">z-10</span> <span class="hljs-attr">origin-bottom</span> <span class="hljs-attr">divide-zinc-100</span> <span class="hljs-attr">rounded-md</span>`}               <span class="hljs-attr">style</span>=<span class="hljs-string">{timing.updateHours}</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
...
</code></pre>
<p>The logic behind the clock hands' movement is found within the <code>useClock</code> hook, specifically in this code snippet:</p>
<pre><code class="lang-javascript">...
setTiming({
 <span class="hljs-attr">updateSeconds</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">`rotate(<span class="hljs-subst">${currentTime.getSeconds() * <span class="hljs-number">6</span>}</span>deg)`</span> },
 <span class="hljs-attr">updateMinutes</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">`rotate(<span class="hljs-subst">${currentTime.getMinutes() * <span class="hljs-number">6</span>}</span>deg)`</span> },
 <span class="hljs-attr">updateHours</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">`rotate(<span class="hljs-subst">${currentTime.getHours() * <span class="hljs-number">30</span> + currentTime.getMinutes() / <span class="hljs-number">2</span>}</span>deg)`</span>,
      },
})
...
</code></pre>
<blockquote>
<p>In an analog clock, the minute and second hands complete a full rotation of 360 degrees within 60 units (minutes or seconds). Therefore, to determine the rotation degree for each unit, we divide 360 by 60, which equals 6. This means that each minute or second is represented by 6 degrees of rotation.</p>
<p>For the hour hand, we multiply by 30 because there are only twelve hours, and a full rotation of 360 degrees within 12 units equals 30. This means that each hour is represented by 30 degrees of rotation.</p>
</blockquote>
<h2 id="heading-children-logic">Children logic</h2>
<h3 id="heading-clock-ticking">Clock ticking</h3>
<p>For audio manipulation, we encapsulated the logic within a hook called <code>useAudio</code>. This hook manages an HTML native audio element that receives a URL containing the source and an update function that toggles the audio on and off. This is controlled by a checkbox in the view.</p>
<h3 id="heading-size-handling">Size handling</h3>
<p>The size is handled with the <code>useSize</code> hook. It contains three important pieces to keep the state:</p>
<ul>
<li><p><code>size</code> =&gt; handles the styles for each size</p>
</li>
<li><p><code>lastSize</code> =&gt; determines what was the last known size</p>
</li>
<li><p><code>updateSize</code> =&gt; updates the state based on the newly selected size by the user</p>
</li>
</ul>
<p>The state is persisted in the browser's local storage.</p>
<h3 id="heading-theme-handling">Theme handling</h3>
<p>The same strategy was employed for theme handling; it is controlled by the <code>useTheme</code> hook. This hook includes a theme object for styling and an <code>updateTheme</code> function for setting the new theme selected by the user. The state is also persisted in the browser's local storage.</p>
<h3 id="heading-responsiveness">Responsiveness</h3>
<p>The component checks for a mobile device type using the <code>useDeviceType</code> hook. This, for instance, allows restricting the user from selecting the larger size of the clock that breaks the UI on small devices.</p>
<h3 id="heading-defining-clock-sizes">Defining Clock Sizes</h3>
<p>We define a function <code>getClockSize</code> that returns the size of the clock, the size of the numbers, and the sizes of the hands based on the <code>clockSize</code> prop.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> getClockSize = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">switch</span> (clockSize) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">'large'</span>:
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">size</span>: <span class="hljs-string">'w-96 h-96'</span>,
          <span class="hljs-attr">numbers</span>: <span class="hljs-string">'inset-5 text-3xl'</span>,
          <span class="hljs-attr">center</span>: <span class="hljs-string">'h-4 w-4 -bottom-[3px]'</span>,
          <span class="hljs-attr">hands</span>: { 
            <span class="hljs-attr">hour</span>: <span class="hljs-string">'h-[6.5em] w-1.5'</span>, 
            <span class="hljs-attr">minute</span>: <span class="hljs-string">'h-[7em] w-1'</span>, 
            <span class="hljs-attr">second</span>: <span class="hljs-string">'h-[9em] w-1'</span> 
          },
        }

      <span class="hljs-keyword">case</span> <span class="hljs-string">'medium'</span>:
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">size</span>: <span class="hljs-string">'w-56 h-56'</span>,
          <span class="hljs-attr">numbers</span>: <span class="hljs-string">'inset-2 text-xl'</span>,
          <span class="hljs-attr">center</span>: <span class="hljs-string">'h-2.5 w-2.5 bottom-[2px]'</span>,
          <span class="hljs-attr">hands</span>: {
            <span class="hljs-attr">hour</span>: <span class="hljs-string">'h-[4.5em] w-[0.35em]'</span>,
            <span class="hljs-attr">minute</span>: <span class="hljs-string">'h-[4.8em] w-[0.2em]'</span>,
            <span class="hljs-attr">second</span>: <span class="hljs-string">'h-[5.4em] w-0.5'</span>,
          },
        }

      <span class="hljs-attr">default</span>:
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">size</span>: <span class="hljs-string">'w-40 h-40'</span>,
          <span class="hljs-attr">numbers</span>: <span class="hljs-string">'inset-1 text-lg'</span>,
          <span class="hljs-attr">center</span>: <span class="hljs-string">'h-2 w-2 bottom-[2px]'</span>,
          <span class="hljs-attr">hands</span>: {
            <span class="hljs-attr">hour</span>: <span class="hljs-string">'h-[2.8em] w-[0.2em]'</span>,
            <span class="hljs-attr">minute</span>: <span class="hljs-string">'h-[3.3em] w-[0.15em]'</span>,
            <span class="hljs-attr">second</span>: <span class="hljs-string">'h-[3.6em] w-0.5'</span>,
          },
        }
    }
}
</code></pre>
<p>Here's a breakdown of how the function works:</p>
<ol>
<li><p>The <code>switch</code> statement is used to evaluate the <code>clockSize</code> variable and determine the appropriate configuration for the clock based on its value.</p>
</li>
<li><p>The <code>clockSize</code> can be <code>'large', 'medium' or 'small'</code>, whatever the size, the function returns an object containing the following properties:</p>
<ul>
<li><p><code>size</code>: A string representing the width and height of the clock (ex. <code>'w-96 h-96'</code>).</p>
</li>
<li><p><code>numbers</code>: A string representing the styling for the hour numbers (ex. <code>'inset-5 text-3xl'</code>).</p>
</li>
<li><p><code>center</code>: A string representing the styling for the center dot of the clock (ex. <code>'h-4 w-4 -bottom-[3px]'</code>).</p>
</li>
<li><p><code>hands</code>: An object with properties representing the styling for the hour, minute, and second hands. Each property is a string of Tailwind CSS classes.</p>
</li>
</ul>
</li>
</ol>
<p>The purpose of this function is to provide a way to dynamically generate the appropriate styling configurations for different sizes of analog clocks based on the <code>clockSize</code> parameter. Encapsulating the configurations in this function allows for flexibility and reusability when creating analog clocks with different sizes and styles.</p>
<p>We call this function and store the result in <code>clockUI</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> clockUI = getClockSize()
</code></pre>
<h3 id="heading-defining-themes">Defining Themes</h3>
<p>The clock includes three predefined themes for testing purposes, but it is designed to be extensible, allowing you to add as many themes as you need or remove those that don't make sense or simply don't appeal to you 😵‍💫</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> AVALIABLE_THEMES = [
  {
    <span class="hljs-attr">key</span>: <span class="hljs-string">'dark'</span>,
    <span class="hljs-attr">value</span>: {
      <span class="hljs-attr">main</span>: <span class="hljs-string">'bg-slate-900 text-slate-300'</span>,
      <span class="hljs-attr">shadow</span>: <span class="hljs-string">'shadow-xl shadow-slate-400'</span>,
      <span class="hljs-attr">hand</span>: {
        <span class="hljs-attr">center</span>: <span class="hljs-string">'bg-slate-200 before:bg-slate-800'</span>,
        <span class="hljs-attr">second</span>: <span class="hljs-string">'bg-slate-300'</span>,
        <span class="hljs-attr">minute</span>: <span class="hljs-string">'bg-slate-300'</span>,
        <span class="hljs-attr">hour</span>: <span class="hljs-string">'bg-slate-300'</span>,
      },
    },
  },
  {
    <span class="hljs-attr">key</span>: <span class="hljs-string">'light'</span>,
    <span class="hljs-attr">value</span>: {
      <span class="hljs-attr">main</span>: <span class="hljs-string">'bg-slate-300 text-slate-800'</span>,
      <span class="hljs-attr">shadow</span>: <span class="hljs-string">'shadow-xl shadow-slate-400'</span>,
      <span class="hljs-attr">hand</span>: {
        <span class="hljs-attr">center</span>: <span class="hljs-string">'bg-slate-800 before:bg-slate-300'</span>,
        <span class="hljs-attr">second</span>: <span class="hljs-string">'bg-slate-800'</span>,
        <span class="hljs-attr">minute</span>: <span class="hljs-string">'bg-slate-600'</span>,
        <span class="hljs-attr">hour</span>: <span class="hljs-string">'bg-slate-600'</span>,
      },
    },
  },
  {
    <span class="hljs-attr">key</span>: <span class="hljs-string">'neutral'</span>,
    <span class="hljs-attr">value</span>: {
      <span class="hljs-attr">main</span>: <span class="hljs-string">'bg-neutral-300 text-teal-700'</span>,
      <span class="hljs-attr">shadow</span>: <span class="hljs-string">'ring-offset-[2px] ring-[10px] shadow-[10px 5px 10px rgba(0, 0, 0, 1)]'</span>,
      <span class="hljs-attr">hand</span>: {
        <span class="hljs-attr">center</span>: <span class="hljs-string">'bg-teal-700 before:bg-neutral-300'</span>,
        <span class="hljs-attr">second</span>: <span class="hljs-string">'bg-teal-600'</span>,
        <span class="hljs-attr">minute</span>: <span class="hljs-string">'bg-teal-700'</span>,
        <span class="hljs-attr">hour</span>: <span class="hljs-string">'bg-teal-700'</span>,
      },
    },
  },
]
</code></pre>
<p>The same approach utilized in clock sizing was employed here. Since multiple parts of the component can be modified, a section for it has been incorporated into the template.</p>
<h2 id="heading-wrapping-up"><strong>Wrapping Up</strong></h2>
<p>And there you have it!</p>
<p>We've built a simple yet effective analog clock component in React. This component not only displays the current time, but it also updates itself every second to keep the time accurate. Additionally, we've added the ability to customize the size of the clock, templating and ticking functionality, giving us more flexibility in how we use this component in our applications.</p>
<p>Remember, this is an opinionated implementation, there are many ways you can extend/modify this component. You could add different themes, change the style of the clock hands, add a different ticking sound, or even make the clock interactive. The possibilities are endless when you're building with React.</p>
<p>Hopefully, this tutorial has helped you understand how to build dynamic components in React and gives you some ideas for your projects.</p>
<p>Happy coding!</p>
<h2 id="heading-bonus">Bonus</h2>
<p><a target="_blank" href="https://github.com/aiherrera/analog-clock">Here</a> you can find the repository and there is a live version at <a target="_blank" href="https://stackblitz.com/edit/aiherrera-analog-clock">Stackblitz</a>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://stackblitz.com/edit/aiherrera-analog-clock?embed=1&amp;hideExplorer=1&amp;hideNavigation=1&amp;view=preview">https://stackblitz.com/edit/aiherrera-analog-clock?embed=1&amp;hideExplorer=1&amp;hideNavigation=1&amp;view=preview</a></div>
<p> </p>
<p>Thank you for reading! Any constructive feedback is greatly appreciated!</p>
]]></content:encoded></item><item><title><![CDATA[Vite-based Starter Kit for React Apps without Using Frameworks]]></title><description><![CDATA[🔄 Git Repository updates

Switched to Bun Toolkit



Updated all dependencies



Introduction
Have you ever needed to prepare ASAP(as usual) a quick demonstration to be shown or just wanted to develop an idea that hit you out of the blue?
In this tu...]]></description><link>https://blog.aiherrera.com/vite-based-starter-kit-for-react-apps-without-using-frameworks</link><guid isPermaLink="true">https://blog.aiherrera.com/vite-based-starter-kit-for-react-apps-without-using-frameworks</guid><category><![CDATA[vite]]></category><category><![CDATA[React]]></category><category><![CDATA[proofOfConcept]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Tue, 09 May 2023 15:23:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683645755501/151ef50c-0528-43d9-ba85-bbe927f972b3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-git-repository-updates">🔄 Git Repository updates</h3>
<ul>
<li>Switched to Bun Toolkit</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695664882256/3d0e2c7b-0d7b-4297-9c2f-c4f8ecee243b.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Updated all dependencies</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695664994464/02df5fab-9fe1-404e-bd56-9a7a6a406e37.png" alt /></p>
<hr />
<h2 id="heading-introduction"><strong>Introduction</strong></h2>
<p>Have you ever needed to prepare ASAP(as usual) a quick demonstration to be shown or just wanted to develop an idea that hit you out of the blue?</p>
<p>In this tutorial, we will be constructing a React application utilizing <a target="_blank" href="https://vitejs.dev/">Vite</a> as our primary development server. It would be the most minimal setup to create quick Proof Of Concepts ASAP.</p>
<p><img src="https://imgs.search.brave.com/Lx75Oa1-pESpgpYYmlB66_IOZ3waJ6OGyWzKdQE8CTY/rs:fit:860:0:0/g:ce/aHR0cDovL3d3dy5x/dWlja21lbWUuY29t/L2ltZy9jZS9jZTY4/OTRiMmRjMzI3ZDgw/Y2RkMGYxNDEyMTJl/OTk4NWJmNTBlMzBm/NjdlYjc0NjIyOGYy/OTZlYjk0NjYxNmY4/LmpwZw" alt="Complete your tasks as asap as possible - Michael Scott" class="image--center mx-auto" /></p>
<p><strong>Vite is a next-generation front-end</strong> build tool and development server, created by <a target="_blank" href="https://evanyou.me/">Evan You</a>, the creator of <a target="_blank" href="https://vuejs.org/">Vue.js</a>, that offers a fast and efficient development experience, is built on top of <a target="_blank" href="https://esbuild.github.io/">esbuild</a>, a JavaScript bundler written in Go, which bundles dependencies 10 to 100 times faster than JavaScript-based bundlers. It doesn't require bundling the entire app or transpiling modules and code. In Vite, transpiling occurs on-demand, resulting in a significantly faster process compared to Create React App (<a target="_blank" href="https://create-react-app.dev/">CRA</a>).</p>
<p>Our application will feature a simple yet interactive counter that can be both incremented and decremented through the use of dedicated buttons.</p>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>Before we get started, make sure you have Node.js and npm installed on your computer. You can download them from <a target="_blank" href="https://nodejs.org/en/download/"><strong>https://nodejs.org/en/download/</strong></a>.</p>
<h3 id="heading-initializing-a-new-project"><strong>Initializing a new project</strong></h3>
<p>First, we need to initialize a new npm package. Open your terminal and navigate to the directory where you want to create your project. Then run the following command:</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p>This will create a new <code>package.json</code> file in your project directory with default values.</p>
<h3 id="heading-installing-dependencies"><strong>Installing dependencies</strong></h3>
<p>Next, we need to install Vite and the necessary React dependencies. Run the following command in your terminal:</p>
<pre><code class="lang-bash">npm install vite react react-dom
</code></pre>
<p>This will install Vite as a development dependency and React and React DOM as regular dependencies.</p>
<h3 id="heading-setting-up-the-development-server"><strong>Setting up the development server</strong></h3>
<p>Now that we have our dependencies installed, we can create a new directory called <code>src</code> in the project root and create the following files inside it:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// App.jsx</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Counter <span class="hljs-keyword">from</span> <span class="hljs-string">'./Counter'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My React App<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Counter</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// Counter.jsx</span>
<span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleIncrement</span>(<span class="hljs-params"></span>) </span>{
    setCount(count + <span class="hljs-number">1</span>);
  }

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleDecrement</span>(<span class="hljs-params"></span>) </span>{
    setCount(count - <span class="hljs-number">1</span>);
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Count: {count}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleIncrement}</span>&gt;</span>Increment<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleDecrement}</span>&gt;</span>Decrement<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Counter;
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// main.jsx</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;

ReactDOM.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>));
</code></pre>
<p>Finally, create a new file called <code>index.html</code> in the project root with the following contents:</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- index.html --&gt;</span>
<span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My new POC<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/src/main.jsx"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This file will be used by Vite to serve our React app.</p>
<h3 id="heading-starting-the-development-server"><strong>Starting the development server</strong></h3>
<p>To start the development server, run the following command in your terminal:</p>
<pre><code class="lang-bash">vite
</code></pre>
<p>This will start the development server on <a target="_blank" href="http://127.0.0.1:5173/">http://127.0.0.1:5173/</a>. You should be able to see your React app by navigating to that URL in your browser.</p>
<p>Additionally, you can specify the desired port for serving your app by using the <code>--host</code> flag.</p>
<pre><code class="lang-xml">vite --host 3003
</code></pre>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<p>I have encountered numerous situations where I don't want to create an app using CRA or Next just to experiment with a proof of concept, an example, or for demonstration purposes.</p>
<p>With this streamlined, minimal setup, I've successfully achieved my goals, and I wanna you to achieve them too.</p>
<h2 id="heading-bonus">Bonus</h2>
<p>I've also created a template that you can use for this purpose, which you can find at this <a target="_blank" href="https://github.com/aiherrera/vite-react-starter-template">link</a>.</p>
<p>Also, if you find it useful <a target="_blank" href="https://github.com/aiherrera/vite-react-starter-template/stargazers">Star this repository on GitHub!</a></p>
<p><img src="https://media.tenor.com/taqSRWFOkaQAAAAC/kung-fu-panda.gif" alt="Kungfu Panda Po GIFs | Tenor" class="image--center mx-auto" /></p>
<p>Thank you for reading! Any constructive feedback is greatly appreciated!</p>
]]></content:encoded></item><item><title><![CDATA[Easy Guide to Create a Desktop App with Next.js and Tauri: Step-by-Step]]></title><description><![CDATA[Introduction
Desktop applications have been an essential part of the software industry for decades. With the increasing demand for user-friendly and responsive applications, developers are always on the lookout for better tools and frameworks to crea...]]></description><link>https://blog.aiherrera.com/easy-guide-to-create-a-desktop-app-with-nextjs-and-tauri-step-by-step</link><guid isPermaLink="true">https://blog.aiherrera.com/easy-guide-to-create-a-desktop-app-with-nextjs-and-tauri-step-by-step</guid><category><![CDATA[Next.js]]></category><category><![CDATA[Tauri]]></category><category><![CDATA[template]]></category><dc:creator><![CDATA[Alain Iglesias]]></dc:creator><pubDate>Sun, 07 May 2023 00:37:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683350176991/6332ca12-0035-473a-b77d-24df47b84a2d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Desktop applications have been an essential part of the software industry for decades. With the increasing demand for user-friendly and responsive applications, developers are always on the lookout for better tools and frameworks to create top-quality desktop applications.</p>
<p>Over the years, several desktop application development frameworks have emerged, with each having its strengths and limitations. However, with the rise of web technologies and the growing popularity of cross-platform development, many developers are turning to web-based frameworks to build desktop applications.</p>
<p>In this article, we will explore how Next.js and Tauri can be used together to build high-quality cross-platform desktop applications using web technologies. We will discuss the advantages of using Next.js and Tauri, how they compare to other popular desktop application development frameworks, and some real-world examples of applications built using these technologies.</p>
<h2 id="heading-why-tauri-and-not-other-technologies">Why Tauri and not other technologies?</h2>
<p>When comparing desktop application development frameworks, there are numerous popular options available, such as <a target="_blank" href="https://www.electronjs.org/">Electron</a>, <a target="_blank" href="https://nwjs.io/">NW.js</a>, and <a target="_blank" href="https://openjfx.io/">JavaFX</a>. However, the combination of <a target="_blank" href="https://nextjs.org/">Next.js</a> and <a target="_blank" href="https://tauri.app/">Tauri</a> offers a distinct set of advantages that set them apart from these other frameworks.</p>
<p>Let's take a quick look at the limitations of these frameworks:</p>
<h3 id="heading-electron">Electron</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683350701290/44829e4b-7dae-404e-9bdf-f8e1a6d4b22a.png" alt /></p>
<p>Electron, a widely-used framework, is often criticized for its large memory footprint and slow start-up times, which can negatively impact the user experience. This is primarily because Electron applications bundle an entire Chromium instance, leading to increased resource consumption. This means that even simple applications built with Electron can consume a significant amount of system resources, which can be especially problematic for users with lower-end hardware or those running multiple applications simultaneously. As a result, developers may face challenges in optimizing their applications for performance and efficiency when using Electron as their framework of choice.</p>
<h3 id="heading-nwjs">NW.js</h3>
<p><img src="https://nwjs.io/img/logo.png" alt="NWJS.io" /></p>
<p>NW.js, an alternative popular choice among developers, presents its own unique set of limitations, particularly in terms of providing comprehensive support for Linux platforms. This can pose a significant drawback for developers who aspire to design and develop cross-platform applications that cater to a diverse and extensive range of users, including those who rely on Linux-based systems. Consequently, developers may find themselves struggling to ensure seamless functionality and compatibility across different operating systems when utilizing NW.js as their primary framework.</p>
<h3 id="heading-javafx">JavaFX</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683350439478/010d1a77-f264-456c-a04e-8087ec6a6b5b.png" alt /></p>
<p>JavaFX, a well-established framework, requires developers to have a solid understanding of the Java programming language. This can be a barrier for those who are not well-versed in Java or prefer to work with other languages. This prerequisite can pose a significant challenge for those who may not have a strong background in Java or have a preference for working with alternative programming languages. As a result, the requirement to master Java can potentially create a barrier to entry for some developers, especially when they are tasked with the development of cross-platform applications catering to a diverse and extensive range of users, including those who rely on Linux-based systems.</p>
<hr />
<p>In contrast, Tauri has emerged as a strong contender in the realm of cross-platform development, boasting remarkable compatibility across a wide variety of platforms, including Windows, macOS, and Linux. This enhanced versatility makes these frameworks a more appealing and flexible option for developers who are seeking to create applications that can effortlessly cater to the needs and preferences of users, irrespective of the operating system they employ.</p>
<p>By opting for Tauri, developers can potentially overcome the challenges associated with NW.js and Electron, thereby delivering a more efficient and high-performing application experience to their end users.</p>
<h2 id="heading-setting-up-the-development-environment">Setting up the Development Environment</h2>
<p>Now that we have established a starting point, let's set up our development environment. To accomplish this, we will need to fulfill a few prerequisites, since Tauri is built on top of the Rust language, some additional installations must need to be performed.</p>
<blockquote>
<p>I'll be following the guide for macOS since that's my current operating system but feel free to select the one that matches yours.</p>
</blockquote>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>First, install the Xcode Command Line Tools:</li>
</ul>
<pre><code class="lang-bash">xcode-select --install
</code></pre>
<ul>
<li>Second, install Rust:</li>
</ul>
<pre><code class="lang-bash">curl --proto <span class="hljs-string">'=https'</span> --tlsv1.2 https://sh.rustup.rs -sSf | sh
</code></pre>
<p>If everything goes well, you'll see a log like this one:</p>
<pre><code class="lang-bash">Rust is installed now. Great!
</code></pre>
<h3 id="heading-create-a-nextjs-project">Create a Next.js project</h3>
<p>Now let's create a fresh install of a Next.js application:</p>
<pre><code class="lang-bash">npx create-next-app@latest --use-npm --typescript
</code></pre>
<p>I would call my app <code>my-desktop-app</code>, again name it as you like :)</p>
<blockquote>
<p>Important: Next.js will ask you if you want to try the new and experimental <code>app/</code> directory. You must select <code>No</code> because it does not yet support the <code>next export</code> command.</p>
</blockquote>
<p>Then modify the <code>next.config.js</code> and set the image option <code>unoptimized: true</code>. This is required to use NextJS Image in SSG mode.</p>
<pre><code class="lang-bash">/** @<span class="hljs-built_in">type</span> {import(<span class="hljs-string">'next'</span>).NextConfig} */
const nextConfig = {
  reactStrictMode: <span class="hljs-literal">true</span>,
+ images: {
+   unoptimized: <span class="hljs-literal">true</span>,
+ },
}

module.exports = nextConfig
</code></pre>
<p>and add an <code>export</code> script to your <code>package.json</code> :</p>
<pre><code class="lang-bash">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"my-desktop-app"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"0.1.0"</span>,
  <span class="hljs-string">"private"</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"dev"</span>: <span class="hljs-string">"next dev"</span>,
    <span class="hljs-string">"build"</span>: <span class="hljs-string">"next build"</span>,
 +  <span class="hljs-string">"export"</span>: <span class="hljs-string">"next export"</span>,
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"next start"</span>,
    <span class="hljs-string">"lint"</span>: <span class="hljs-string">"next lint"</span>
  },
...
</code></pre>
<h3 id="heading-create-a-rust-project">Create a Rust project</h3>
<p>As I said before Tauri is built on top of Rust core, so let's add it:</p>
<pre><code class="lang-bash">npm install --save-dev @tauri-apps/cli
</code></pre>
<p>Also, add a <code>tauri</code> script to your <code>package.json</code>:</p>
<pre><code class="lang-bash"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"dev"</span>: <span class="hljs-string">"next dev"</span>,
    <span class="hljs-string">"build"</span>: <span class="hljs-string">"next build"</span>,
    <span class="hljs-string">"export"</span>: <span class="hljs-string">"next export"</span>,
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"next start"</span>,
    <span class="hljs-string">"lint"</span>: <span class="hljs-string">"next lint"</span>,
+   <span class="hljs-string">"tauri"</span>: <span class="hljs-string">"tauri"</span>
  },
...
</code></pre>
<p>Now we are good to go with the project generation:</p>
<pre><code class="lang-bash">npm run tauri init
</code></pre>
<p>After executing that command you should see a similar output log:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683416772587/812ca0f3-58dc-452b-915c-da759b208b3f.png" alt class="image--center mx-auto" /></p>
<p>and a file structure like this one:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683416621915/29637293-c543-4980-aca2-339d424b2c3e.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>I am planning an article that covers more advanced content related to the Tauri project and the Rust language.</p>
</blockquote>
<p>The only step left is to run your project:</p>
<pre><code class="lang-bash">npm run tauri dev
</code></pre>
<p>You should see your Desktop app up and running!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683417468133/e5e997c3-cddd-4d79-885e-d9fd356ea848.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-wrapping-up">Wrapping up!</h2>
<p>That's it, hope you enjoyed this tutorial, now you can start to craft some amazing cross-platform Desktop apps.</p>
<p>Let me in the comments what you have built with Next and Tauri or if you rather prefer another technology!</p>
<h2 id="heading-bonus">Bonus</h2>
<p>As usual, I already have created for you a fully-fledged, configured template with several add-ons in this <a target="_blank" href="https://github.com/aiherrera/nextjs-tauri-template-starter">link</a>:</p>
<ul>
<li><p><a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a> for static type checking</p>
</li>
<li><p><a target="_blank" href="https://eslint.org/">ESLint</a> for code linting</p>
</li>
<li><p><a target="_blank" href="https://prettier.io/">Prettier</a> for code formatting</p>
</li>
<li><p><a target="_blank" href="https://github.com/azz/pretty-quick">Pretty-quick</a> runs prettier over changed files</p>
</li>
</ul>
<p>For git integration, it has also:</p>
<ul>
<li><p><a target="_blank" href="https://www.conventionalcommits.org/en/v1.0.0/">Conventional commits</a> for improving commits</p>
</li>
<li><p><a target="_blank" href="https://github.com/typicode/husky">Husky</a> for improving commits</p>
</li>
</ul>
<p>Thank you for reading! Any constructive feedback is greatly appreciated!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683417829511/bcd4d1a7-c985-4a5a-af5b-8d60f847e5be.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item></channel></rss>