<?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[Joe Attardi]]></title><description><![CDATA[Joe Attardi]]></description><link>https://joeattardi.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 13:13:19 GMT</lastBuildDate><atom:link href="https://joeattardi.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Think before you reach for that div]]></title><description><![CDATA[In the past, web user interfaces were constructed largely using <div> and <span> elements. These are generic block and inline elements that really were your only option other than <p> and a few other elements.
In 2014, when HTML5 was released as a W3...]]></description><link>https://joeattardi.dev/think-before-you-reach-for-that-div</link><guid isPermaLink="true">https://joeattardi.dev/think-before-you-reach-for-that-div</guid><category><![CDATA[HTML5]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Wed, 24 Sep 2025 18:12:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/p9OkL4yW3C8/upload/72c0244981dd0db3ae1e9d3ad381c8a0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the past, web user interfaces were constructed largely using <code>&lt;div&gt;</code> and <code>&lt;span&gt;</code> elements. These are generic block and inline elements that really were your only option other than <code>&lt;p&gt;</code> and a few other elements.</p>
<p>In 2014, when HTML5 was released as a W3C Recommendation, the day of the <code>&lt;div&gt;</code> as the primary building block of web interfaces was over. At least, that was the intent. This brave new world of HTML brought a slew of semantic elements that can - and should - be used over plain <code>&lt;div&gt;</code> elements.</p>
<p>A semantic element is one that provides some context about that element's role in the overall structure of the document. They provide structure, as a <code>&lt;div&gt;</code> does, but also provide meaning. Some examples of common semantic elements are:</p>
<ul>
<li><p><code>&lt;nav&gt;</code></p>
</li>
<li><p><code>&lt;header&gt;</code></p>
</li>
<li><p><code>&lt;main&gt;</code></p>
</li>
<li><p><code>&lt;aside&gt;</code></p>
</li>
</ul>
<h2 id="heading-why-should-i-use-semantic-elements"><strong>Why should I use semantic elements?</strong></h2>
<p>While your app will work perfectly fine with <code>&lt;div&gt;</code> elements, even in modern browsers, there are benefits of using these new semantic elements in your web applications.</p>
<h3 id="heading-accessibility"><strong>Accessibility</strong></h3>
<p>One of the most important reasons to use these elements is accessibility. When the document structure is better described with semantic elements, assistive technologies such as screen readers can give a more accurate outline of the document to a user, making it easier to use and navigate your app.</p>
<p>Using semantic elements won’t solve all of your accessibility concerns - you’ll still need to use ARIA attributes and other techniques - but it goes a long way in helping assistive technologies better understand your app’s layout and structure.</p>
<h3 id="heading-better-seo"><strong>Better SEO</strong></h3>
<p>When a search engine crawls your app to index it, semantic elements help the crawler understand its structure. In particular, it helps the crawler filter out the noise and find your main content, which is the important part to be indexed.</p>
<p>It also helps the crawler identify additional content, navigation, etc. and provides contextual relevance about the different parts of your app.</p>
<p>By helping the crawler identify the important, most relevant parts of your content, you can improve your search results and rankings. Be careful, though. If you use semantic tags incorrectly, this can mislead search engines and cause potential SEO issues.</p>
<h3 id="heading-less-attribute-noise"><strong>Less attribute noise</strong></h3>
<p>When you use semantic elements, you won’t need to use the role attribute as often. Each element has an implicit role, which is a default role that’s assigned without having to explicitly add it to the element. This lets you write, for example, <code>&lt;nav&gt;</code> instead of <code>&lt;div role="navigation"&gt;</code>.</p>
<p>It also makes styling a little easier because you don't have to rely on adding CSS classes as much. For a header, before HTML5 you might have used something like: <code>&lt;div class="header"&gt;</code>. Using semantic elements, this can just be <code>&lt;header&gt;</code> and simplifies your CSS selectors.</p>
<h3 id="heading-better-alignment-with-best-practices"><strong>Better alignment with best practices</strong></h3>
<p>As HTML evolves, semantic elements will likely remain important for the above reasons and others. Using them ensures your site is built with best practices in mind, and will benefit your site as HTML changes in the future.</p>
<p>While <code>&lt;div&gt;</code> elements aren't going anywhere - your site isn't suddenly going to stop working in a browser someday - following these best practices today makes for a better structured HTML document tomorrow.</p>
<h2 id="heading-other-div-antipatterns"><strong>Other</strong> <code>div</code> <strong>antipatterns</strong></h2>
<p>Even before the introduction of HTML5 semantic elements, there have been other places where you should not - and still should not - use a <code>&lt;div&gt;</code>.</p>
<h3 id="heading-buttons"><strong>Buttons</strong></h3>
<p>Here’s a <code>&lt;div&gt;</code> being used as a button, with a CSS class so that you can style it to look like a button:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button"</span>&gt;</span>Click Me<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This has no semantic meaning at all. You can improve it somewhat by adding the <code>button</code> ARIA role:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span>&gt;</span>Click Me<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This semantically identifies the element as a button to assistive technologies, but there's still no way to activate this “button” with the keyboard. For that we have to give it a <code>tabindex</code> of <code>0</code>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"0"</span>&gt;</span>Click Me<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Why do this, when you can simply use a <code>&lt;button</code>\&gt;:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Click Me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<h3 id="heading-lists"><strong>Lists</strong></h3>
<p>Avoid using <code>&lt;div&gt;</code> elements to define a list:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</span>&gt;</span>Item 1<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</span>&gt;</span>Item 2<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>
</code></pre>
<p>Instead, use the proper semantic list elements:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item 1<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Item 2<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>
</code></pre>
<p>You might not want the default list presentation of a bulleted list, with one item per line. However, you can use CSS to give the list any kind of layout you want, while still maintaining the semantic distinction of being a list.</p>
<h2 id="heading-theres-still-a-place-for-divs"><strong>There's still a place for divs</strong></h2>
<p>I’m not a <code>&lt;div&gt;</code> hater. Far from it! I still use <code>&lt;div&gt;</code> and <code>&lt;span&gt;</code> elements all the time, and you can too. These elements are best used inside of a semantic element, where you need some separation for styling purposes. The important thing is that your document uses semantic elements to outline its structure.</p>
<p>You can also use a <code>&lt;div&gt;</code> to group related elements when there isn't a good semantic element to use. For example, if you have a set of action buttons inside of a semantic container like <code>&lt;article&gt;</code> or <code>&lt;section&gt;</code>, you can group these buttons inside a <code>&lt;div&gt;</code>.</p>
<p>As a general rule, consider the semantic meaning of your content. If there isn't a semantic element that fits your intent, it's probably okay to use a <code>&lt;div&gt;</code> or <code>&lt;span&gt;</code>.</p>
<h2 id="heading-summary"><strong>Summary</strong></h2>
<ul>
<li><p>Wherever possible, use semantic HTML elements such as <code>&lt;header&gt;</code>, <code>&lt;section&gt;</code>, <code>&lt;nav&gt;</code>, etc.</p>
</li>
<li><p>It helps with accessibility, SEO, and spec compliance.</p>
</li>
<li><p>Try not to recreate built-in elements like buttons and lists by using <code>&lt;div&gt;</code> elements. Instead, use the proper semantic element (<code>&lt;button&gt;</code>, <code>&lt;ul&gt;</code>, etc.).</p>
</li>
<li><p><code>&lt;div&gt;</code> elements still have their place, but check to see if there's a semantic element you can use first.</p>
</li>
</ul>
<h2 id="heading-further-reading"><strong>Further reading</strong></h2>
<ul>
<li><p>freeCodeCamp has a great overview of <a target="_blank" href="https://www.freecodecamp.org/news/semantic-html5-elements/"><strong>semantic HTML5 elements</strong></a>.</p>
</li>
<li><p>MDN's <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element"><strong>reference of HTML elements</strong></a> includes the semantic elements.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Is vibe coding the future?]]></title><description><![CDATA[The concept of “vibe coding” was first introduced by Andrej Karpathy in an X post from February 2025:

There's a new kind of coding I call "vibe coding", where you fully give in to the vibes, embrace exponentials, and forget that the code even exists...]]></description><link>https://joeattardi.dev/is-vibe-coding-the-future</link><guid isPermaLink="true">https://joeattardi.dev/is-vibe-coding-the-future</guid><category><![CDATA[AI]]></category><category><![CDATA[vibe coding]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Sun, 23 Mar 2025 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765853643976/c69d4c40-ec58-4adb-9c6b-8560893ee5bf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The concept of “vibe coding” was first introduced by Andrej Karpathy in an <a target="_blank" href="https://x.com/karpathy/status/1886192184808149383"><strong>X post</strong> from</a> February 2025:</p>
<blockquote>
<p><strong><em>There's a new kind of coding I call "vibe coding", where you fully give in to the</em></strong> <a target="_blank" href="https://x.com/karpathy/status/1886192184808149383"><strong><em>vibes</em></strong></a><strong><em>, embrace exponentials, and forget that the code even exists. It's possible because the LLMs (e.g. Cursor Composer w Sonnet) are getting too good. Also I just talk to Composer with SuperWhisper so I barely even touch the keyboard.</em></strong></p>
</blockquote>
<p>Since then, the concept has caught on and people have been using this technique to build all kinds of things.</p>
<p>There are strong opinions on both sides. It seems to be particularly popular with the “indie hacker” crowd.</p>
<p>Vibe coding, to me, seems like a good way to prototype something in a short period of time. I experimented with it recently, using Cursor and nothing but its agent mode to build a fully functional toast notification web component, complete with notification stacking and nice animations.</p>
<p>I wrote a specification of what I wanted, it built it, and fixed all the bugs that I found. I had a fully working web component with all the bells and whistles in about an hour. I didn't write any code, and just accepted all of Cursor's proposed changes. I was seriously impressed with the final product.</p>
<p>However, without studying and understanding the code that was generated, I don't feel comfortable publishing this component as an npm package. Some might say that taking this step would defeat the purpose of vibe coding. Maybe it does, but I wouldn't want to put work out there with my name on it without a full understanding of what it does.</p>
<p>There have been several incidents I've seen on X where someone built a whole app using the vibe coding approach, and deployed it without fully understanding it or its security vulnerabilities, and the app was hit with malicious attacks.</p>
<p>It's tempting to think you can bootstrap a SaaS in a weekend using the vibe coding approach, but as these folks found out, there's more to building an app than writing a bunch of code. You need to understand the security risks and other issues, and how to mitigate them to make sure you don't end up with a surprise $25,000 Vercel bill.</p>
<p>Personally, I don't think vibe coding is a practical way for a less technical person to build an app. There are too many gaps in knowledge, since the AI can only create what you ask it to. If you're in such a position, you're much better off using a no-code platform, something like <a target="_blank" href="https://bubble.io/"><strong>Bubble</strong></a>, to build your full stack app.</p>
<p>If you are a technical person, though, I think this is a fine approach to throw together a proof of concept of something you want to build. If you really study and understand the code that's generated (and fix issues that you find!), it might even be a good starting point for a real-world app.</p>
<p>As AI models get more capable of writing code, I think it's only natural that we will start to use them more to build things. I think this is particularly true with front-end code (which has me a little nervous, since that's what I do!).</p>
<p>To answer the question posed by this post's title - no, I don't think vibe coding is the future. It's definitely another tool for the AI toolbox, but in my opinion you're asking for trouble if you use this approach to build and deploy an entire app without putting in the work to understand it, audit it, and make sure there aren't vulnerabilities.</p>
<p>Having said all that - it's damn impressive what I have seen Cursor's agent mode be able to do. Going back to my toast notification web component, I started with an empty directory and Cursor did the rest. If I get around to it, I might learn how it works, clean it up, and maybe I'll publish it one of these days.</p>
<p>Having AI generate some code based on a problem statement is impressive, but I think the real superpower is that it can iterate on the result. Found a bug, or don't like how it turned out? Just have a conversation and watch the code improve.</p>
<p>For another recent project I build, a tool called <a target="_blank" href="https://urlscrub.com/"><strong>URL Scrub</strong></a> (check it out!), I used Vercel's <a target="_blank" href="https://v0.dev/"><strong>v0.dev</strong></a> to design the UI. I have adopted v0 as my UI designer for most of the side projects I build now, but I usually end up still writing the code myself.</p>
<p>In summary - while I am a big proponent of using AI tools as part of my software development workflow, I don't see vibe coding as a good approach for building something production-ready to deploy in the real world. With time, maybe this will change, but as of now, in mid-2025, I think that's where we're at.</p>
]]></content:encoded></item><item><title><![CDATA[4 years of "Modern CSS"]]></title><description><![CDATA[It's October 2024, and I am celebrating four years as a published author. According to Amazon, Modern CSS was published on October 7, 2020. Modern CSS actually started out as a self-published book on Leanpub (a great platform for self-publishing book...]]></description><link>https://joeattardi.dev/4-years-of-modern-css</link><guid isPermaLink="true">https://joeattardi.dev/4-years-of-modern-css</guid><category><![CDATA[writing]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Sun, 27 Oct 2024 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/03UCoidYvXw/upload/4f8e29d24afbc7a58c196f3523625a88.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It's October 2024, and I am celebrating four years as a published author. According to Amazon, <em>Modern CSS</em> was published on October 7, 2020. <em>Modern CSS</em> actually started out as a self-published book on Leanpub (a great platform for self-publishing books).</p>
<p>It was actually my second book; my first book was called <em>Using Gatsby and Netlify CMS</em>. This was a very niche book that covered one very specific stack (one that has, since, fallen out of favor. Gatsby is not as popular as it once was, and Netlify CMS lives on as Decap CMS). The book was a little too niche and barely sold at all.</p>
<p><img src="https://joeattardi.com/blog/modern-css-cover-old.png" alt="The cover of the self-published version of &quot;Modern CSS&quot;" class="image--center mx-auto" /></p>
<h2 id="heading-getting-published"><strong>Getting published</strong></h2>
<p>After publishing <em>Modern CSS</em> on Leanpub, it sold very little. I don't have much of a following online - back in 2020 it was even less than it is now - so I was trying to think of a way to get it in front of a wider audience.</p>
<p>I took a look at different publishers, and decided to look into possibly getting the book published with Apress. I was a first time book author and didn't know anything about the process of getting published; surely, they wouldn't be interested in an unsolicited book proposal from a relative unknown!</p>
<p>Luckily I was wrong. To my surprise, Apress was interested in publishing the book. I would take it down from Leanpub and rework the book for Apress's format. It only took a couple of months to rework the whole book. My first contact with Apress was in June 2020, and the book was out by October. It happened so fast, and it was all done over email!</p>
<p><img src="https://joeattardi.com/blog/modern-css-cover.jpg" alt="Modern CSS cover" class="image--center mx-auto" /></p>
<h2 id="heading-becoming-an-oreilly-author"><strong>Becoming an O'Reilly author</strong></h2>
<p><img src="https://joeattardi.com/blog/web-api-cookbook-cover.jpg" alt="The cover of &quot;Web API Cookbook&quot;" class="image--center mx-auto" /></p>
<p>After a while, I started getting the itch to write again. My editor from Apress had moved on and now worked at O'Reilly Media. I had a rough idea for a book about the web platform, highlighting the different APIs and technologies available in modern browsers.</p>
<p>I reached out to my old editor and she put me in touch with another editor at O'Reilly to discuss the proposal. Once again, I was pleasantly surprised - they were interested in the book, and thought it would be a good for their "Cookbook" series of books. It was tentatively titled <em>Web Browser API Cookbook</em>, and I started working on it in February 2023.</p>
<p>The writing process with O'Reilly was fantastic. The book was written using Asciidoc, which is sort of like Markdown but with some more bells and whistles. The book content lived in a Git repository and I wrote it using Visual Studio Code.</p>
<p>Getting closer to publication, it was decided to rename the book to just <em>Web API Cookbook</em>. It rolls off the tongue a little better than <em>Web Browser API Cookbook</em>, I must admit. I finished writing almost a year later, in early 2024. Then, in April, the book was published. I couldn't believe that I was now an O'Reilly author and had my own book with an animal on the cover!</p>
<h2 id="heading-whats-next"><strong>What's next</strong></h2>
<p>Despite the books not being best sellers, I enjoyed writing them and am very proud of them. I'd love to do another book when the time is right and when there's a good topic. (Got any good ideas for a book about web development?) Or, maybe there will be a second edition of <em>Modern CSS</em> or <em>Web API Cookbook</em> someday. There is certainly enough change in the worlds of CSS and browser APIs to provide enough new content!</p>
<p>Do you have an idea for a book you'd like to write? Pitch it to a publisher - you never know!</p>
<p>If you'd like to check out my books, you can find them on Amazon:</p>
<ul>
<li><p><a target="_blank" href="https://www.amazon.com/Web-API-Cookbook-JavaScript-Applications/dp/1098150694"><strong>Web API Cookbook</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.amazon.com/Modern-CSS-Master-Concepts-Development/dp/148426293X"><strong>Modern CSS</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Beyond breakpoints: Leveraging user preference media queries in CSS]]></title><description><![CDATA[If you build web sites or apps, chances are you work with media queries. These handy CSS tools allow you to adjust your layout depending on the size of the device. They are a key part of responsive design.
You can query based on the width of the devi...]]></description><link>https://joeattardi.dev/beyond-breakpoints-leveraging-user-preference-media-queries-in-css</link><guid isPermaLink="true">https://joeattardi.dev/beyond-breakpoints-leveraging-user-preference-media-queries-in-css</guid><category><![CDATA[CSS]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Tue, 22 Oct 2024 04:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765853253261/ca48ac3d-eddc-498b-831f-a654a7f9c810.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you build web sites or apps, chances are you work with media queries. These handy CSS tools allow you to adjust your layout depending on the size of the device. They are a key part of responsive design.</p>
<p>You can query based on the width of the device, its aspect ratio, orientation, and more. These all allow you to fine-tune your layout for the device being used.</p>
<p>You might not know that there are other media queries available that let you tailor your site or app based on the user's preferences rather than their device size and orientation.</p>
<h2 id="heading-user-preference-media-queries"><strong>User preference media queries</strong></h2>
<p>There are several media queries that deal with user preferences. You can use these to fine tune your app's experience for the user.</p>
<h2 id="heading-automatic-dark-mode-with-prefers-color-scheme"><strong>Automatic dark mode with</strong> <code>prefers-color-scheme</code></h2>
<p>Dark mode is everywhere these days. It seems like every site now has the sun/moon toggle button to switch between light mode and dark mode. You can take this one step further and use the <code>prefers-color-scheme</code> media query to automatically determine if the user's device is using a light or dark color mode.</p>
<p>Here's how it works: Define your CSS styles for light mode like you normally would. Then add the media query <code>prefers-color-scheme: dark</code>. In there, add CSS rules overriding your light mode colors:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.content</span> {
  <span class="hljs-attribute">background-color</span>: white;
  <span class="hljs-attribute">color</span>: black;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-color-scheme:</span> dark) {
  <span class="hljs-selector-class">.content</span> {
    <span class="hljs-attribute">background-color</span>: black;
    <span class="hljs-attribute">color</span>: white;
  }
}
</code></pre>
<h3 id="heading-tip-create-themes-with-css-variables"><strong>Tip: Create themes with CSS variables</strong></h3>
<p>To make life a little easier, you can define all your colors in a theme, a set of CSS variables. Then inside your <code>prefers-color-scheme: dark</code> block, you only need to redefine the variables instead of re-adding your CSS selectors and rules:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--main-background</span>: white;
  <span class="hljs-attribute">--text-color</span>: black;
}

<span class="hljs-selector-class">.content</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--main-background);
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--text-color);
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-color-scheme:</span> dark) {
  <span class="hljs-selector-tag">--main-background</span>: <span class="hljs-selector-tag">black</span>;
  <span class="hljs-selector-tag">--text-color</span>: <span class="hljs-selector-tag">white</span>;
}
</code></pre>
<h2 id="heading-tone-down-animations-with-prefers-reduced-motion"><strong>Tone down animations with</strong> <code>prefers-reduced-motion</code></h2>
<p>Animations can enhance your app's experience, but animations may be difficult for users with vision or vestibular problems. To assist these users, some devices and operating systems have an option in the user preferences to reduce motion.</p>
<p>You can use the <code>prefers-reduced-motion</code> media query to detect when such an option is enabled for the user's device. You can then use alternate animations that are less intense (or turn them off altogether).</p>
<p>Here's an example of using <code>prefers-reduced-motion</code> to turn off an animation.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.content</span> {
  <span class="hljs-attribute">animation</span>: my-awesome-animation <span class="hljs-number">250ms</span> ease-in-out;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-reduced-motion:</span> reduce) {
  <span class="hljs-selector-class">.content</span> {
    <span class="hljs-attribute">animation</span>: none;
  }
}
</code></pre>
<p>One thing to note: If you turn off animations like this, make sure you don't have any code that relies on an <code>animationend</code> event. When you set <code>animation</code> to <code>none</code>, as shown above, this event will never be fired.</p>
<p>Keep in mind that you don't have to turn off animations when <code>prefers-reduced-motion: reduce</code> matches! Suppose you have a fancy reveal animation where the element bounces into view. When the user wants reduced motion, you could change this so it's a simple fade-in animation.</p>
<h2 id="heading-adaptive-contrast-with-prefers-contrast"><strong>Adaptive contrast with</strong> <code>prefers-contrast</code></h2>
<p>Some users with vision difficulties may have increased contrast enabled on their device. You can handle such situations with the <code>prefers-contrast</code> media query.</p>
<p>If this media query matches, you can adjust your contrast to make things easier to see for these users.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid gray;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-contrast:</span> more) {
  <span class="hljs-selector-class">.box</span> {
    <span class="hljs-comment">/* Make the border stand out more against the background */</span>
    <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid black;
  }
}
</code></pre>
<h2 id="heading-checking-media-queries-with-javascript"><strong>Checking media queries with JavaScript</strong></h2>
<p>Suppose you're animating with JavaScript - for example, maybe you're using the Web Animations API. Since these animations aren't defined in the CSS, you can't turn them off with the <code>prefers-reduced-motion</code> media query.</p>
<p>Or can you?</p>
<p>Yes! You can use the <code>window.matchMedia</code> method to evaluate a media query from JavaScript. The media query is passed as an argument, and the method returns something called a <code>MediaQueryList</code>.</p>
<p>This object has a <code>matches</code> property, which is a boolean indicating whether or not this media query currently matches. Based on the value, you can decide whether or not to animate.</p>
<p>Here's a simple example showing how <code>window.matchMedia</code> can be used to conditionally call <code>animate</code> on a DOM element:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Check to see if we should animate</span>
<span class="hljs-keyword">const</span> query = <span class="hljs-built_in">window</span>.matchMedia(<span class="hljs-string">'(prefers-reduced-motion: reduce)'</span>);
<span class="hljs-keyword">if</span> (!query.matches) {
  someElement.animate(...);
}
</code></pre>
<h3 id="heading-reacting-to-changes"><strong>Reacting to changes</strong></h3>
<p>A <code>MediaQueryList</code> even has a <code>change</code> event which fires if conditions change and the media query no longer applies.</p>
<p>Suppose you have some JavaScript code that you only want to run for large displays. If the user's screen size is small, you want to skip this code. You can do this by calling <code>window.matchMedia</code> using a <code>max-width</code> query or something similar.</p>
<p>Suppose that later, the user resizes the window, and now you want to run the large screen specific JavaScript code. Just listen for the <code>MediaQueryList</code>'s <code>change</code> event, and you can check the event's <code>matches</code> property to see what the new value is.</p>
<h2 id="heading-summary"><strong>Summary</strong></h2>
<p>These media queries can help you to better personalize your user's experience within your website or app. You can automatically apply a dark color scheme, and even fine-tune your animations and contrast depending on user preferences. They also help with accessibility, which is always a win.</p>
<p>It's still in an experimental stage, but you can also keep an eye out for the <code>prefers-reduced-data</code> query which will indicate whether the user's device has a requirement that is uses less data. This can be used to provide alternate content that uses less data. For example, you could skip non-essential images (or use lower-resolution versions).</p>
]]></content:encoded></item><item><title><![CDATA[Using git bisect, the detective tool for debugging]]></title><description><![CDATA[You’re working on a bug fix and find some bad code that causes a bug. The git blame command will tell you who the last developer was that modified that line, and when they modified it. But what if you don’t know what code introduced the bug? For thes...]]></description><link>https://joeattardi.dev/using-git-bisect-the-detective-tool-for-debugging</link><guid isPermaLink="true">https://joeattardi.dev/using-git-bisect-the-detective-tool-for-debugging</guid><category><![CDATA[Git]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Fri, 04 Oct 2024 03:19:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/d9ILr-dbEdg/upload/873e9847240212a2047735c69bffd4e5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You’re working on a bug fix and find some bad code that causes a bug. The <code>git blame</code> command will tell you who the last developer was that modified that line, and when they modified it. But what if you don’t know what code introduced the bug? For these situations, the <code>git bisect</code> command can help.</p>
<p>To use <code>git bisect</code>, you’ll need to find a commit where the bug exists (a “bad” commit), and you’ll also need to find an older commit where the bug doesn’t exist (a “good” commit).</p>
<p>Once you identify these two commits, <code>git bisect</code> will guide you through a binary search of the commit history.</p>
<p>This can save you considerable time if there are a lot of commits between the bad commit and the good commit. At each step of the binary search, you perform a test to see if the bug exists. If the bug exists at this commit, you tell <code>git bisect</code> that this is a bad commit. If the bug doesn’t exist, you indicate that it’s a good commit.</p>
<p>Depending on whether the commit is bad or good, <code>git bisect</code> picks another middle point between the commit you identified and the bad commit. The process continues until Git has identified the first bad commit which introduced the bug.</p>
<h2 id="heading-example-bisect">Example bisect</h2>
<p>Let’s walk through a short <code>git bisect</code> and see a visualization of each step.</p>
<p>First, to start the process, run <code>git bisect start</code>:</p>
<pre><code class="lang-plaintext">% git bisect start
status: waiting for both good and bad commits
</code></pre>
<p>Make sure you’ve checked out a commit or branch that exhibits the bug you’re investigating, and run <code>git bisect bad</code>:</p>
<pre><code class="lang-plaintext">% git bisect bad
status: waiting for good commit(s), bad commit known
</code></pre>
<p>Next, you’ll need to check out a known good commit and run <code>git bisect good</code>:</p>
<pre><code class="lang-plaintext">% git checkout &lt;commit ID&gt;
% git bisect good
Bisecting: X revisions left to test after this (roughly Y steps)
</code></pre>
<p>At this point, you’ve identified a good commit and a bad commit, and Git is pointing to a commit in the middle for you to check.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728010888085/69448c77-2e0e-45b8-a0cd-0c9782e95cdb.png" alt class="image--center mx-auto" /></p>
<p>Run or test your code, and see if the bug exists here. If you can’t reproduce the bug, mark this as a good commit by running <code>git bisect good</code>. Now Git knows that the commits between the first good commit and this one are all good:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728011002661/ed89ef9e-7d83-41ce-a02a-c8ee68c68e4c.png" alt class="image--center mx-auto" /></p>
<p>Now, Git will continue the binary search. It will pick the commit in the middle between the good and bad commits, and check it out for you to check:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728011038317/4ba98958-8313-472a-9119-ce23e9225e7c.png" alt class="image--center mx-auto" /></p>
<p>Suppose that here, you are able to reproduce the bug. Mark this as a bad commit by running <code>git bisect bad</code>. Git will mark this commit as bad:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728011085025/f147da6a-ef9c-43ec-b2fd-2a491c491f8d.png" alt class="image--center mx-auto" /></p>
<p>It will pick the next commit between the good and bad commits, and continue binary searching:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728011116141/8efb4af7-6e01-4be4-9529-f4f3f07f7ab2.png" alt class="image--center mx-auto" /></p>
<p>Let’s assume that this is a good commit, and you can’t reproduce the bug. Just as you did before, run <code>git bisect good</code> to mark this as a good commit:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728011147285/31a84a0f-b806-4ff2-a6e6-59468b518c3d.png" alt class="image--center mx-auto" /></p>
<p>At this point, Git has enough information to tell you the first bad commit.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728011163573/d17d4967-e82b-4ee5-8425-7d8cf6e9727e.png" alt class="image--center mx-auto" /></p>
<p>Now you can look at the changes from that commit and, hopefully, determine what change caused the bug.</p>
<p>When you’re done, run <code>git bisect reset</code> to exit bisect mode and return to the commit you were at when you started bisecting.</p>
<h2 id="heading-mixing-up-good-and-bad-commits">Mixing up good and bad commits</h2>
<p><code>git bisect</code> can only work if the good commit is an ancestor of a bad commit. If you mark a commit as good, then check out an earlier commit and mark it as bad, you’ll get an error:</p>
<pre><code class="lang-plaintext">Some good revs are not ancestors of the bad rev.
git bisect cannot work properly in this case.
Maybe you mistook good and bad revs?
</code></pre>
<h2 id="heading-automating-git-bisect">Automating <code>git bisect</code></h2>
<p>It might be tedious to manually test your code at each step of a <code>git bisect</code>, but you might be able to automate it. You can use <code>git bisect run</code> and give it the name of a script or other command to run. Git will check the exit code of the command at each step.</p>
<p>If the exit code is 0, it’s treated as a good commit. If you want the commit to be treated as a bad commit, your command should have an exit code between 1 and 127. However, there is one exception to this. Git reserves the exit code 125 to have a special meaning. If, for some reason, this commit can’t be tested, your command can return an exit code of 125 and it will skip that commit.</p>
<h2 id="heading-summary">Summary</h2>
<p>The <code>git bisect</code> command can help you quickly narrow down which commit introduced a bug or other undesirable behavior. It does this by performing a binary search on the commit history between a known good commit and a known bad commit.</p>
<p>If you have automated tests, you can even use <code>git bisect run</code> to automatically control the process of testing and identifying good and bad commits.</p>
]]></content:encoded></item><item><title><![CDATA[Steps for installing a local AI copilot in Visual Studio Code]]></title><description><![CDATA[Does your company block ChatGPT or GitHub Copilot? Do you have security or trust concerns sending your code to a third party AI service? You might not know this, but you can run a large language model (LLM) locally on your computer, and even integrat...]]></description><link>https://joeattardi.dev/steps-for-installing-a-local-ai-copilot-in-visual-studio-code</link><guid isPermaLink="true">https://joeattardi.dev/steps-for-installing-a-local-ai-copilot-in-visual-studio-code</guid><category><![CDATA[Visual Studio Code]]></category><category><![CDATA[AI]]></category><category><![CDATA[#ai-tools]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Thu, 12 Sep 2024 20:12:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726171888549/4fa00ea3-d573-4af7-bf94-50ecdec10852.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Does your company block ChatGPT or GitHub Copilot? Do you have security or trust concerns sending your code to a third party AI service? You might not know this, but you can run a large language model (LLM) locally on your computer, and even integrate it with Visual Studio Code.</p>
<p>Using the <a target="_blank" href="https://ollama.com">Ollama</a> tool, you can download and run models locally. In this post, I’ll guide you through the steps to run the Code Llama model using Ollama, and integrate it into Visual Studio Code.</p>
<p><a target="_blank" href="https://ollama.com/library/codellama">Code Llama</a> is an LLM from Meta that is focused on generating and talking about code. It’s based on their Llama 2 model, and supports many different languages.</p>
<h2 id="heading-installing-ollama-and-the-code-llama-model">Installing Ollama and the Code Llama model</h2>
<p>Your first step is to install Ollama. Go over to <a target="_blank" href="https://ollama.com/download">https://ollama.com</a> where you can download and install it. Once Ollama is up and running, you should have a new terminal command, <code>ollama</code>. To see if it’s installed correctly, open a terminal and run:</p>
<pre><code class="lang-plaintext">ollama -v
</code></pre>
<p>This should print the Ollama version. If you see this, then you’re good to go! Next, download the Code Llama model by running this command:</p>
<pre><code class="lang-plaintext">ollama pull codellama
</code></pre>
<p>This may take a while, depending on your Internet connection. The 7b version of Code Llama is 3.8 gigabytes. Go get a cup of coffee, tea, or your favorite beverage while Ollama downloads this model.</p>
<h2 id="heading-setting-up-codegpt">Setting up CodeGPT</h2>
<p><a target="_blank" href="https://codegpt.co/">CodeGPT</a> has a Visual Studio Code extension where you can interact with models directly in the editor. In VS Code, go to the Extensions tab and search for “codegpt”. You’ll see several results, make sure to get the one with the blue check mark:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726170993828/1be46d9e-84c7-4870-80c7-25913a59c425.png" alt class="image--center mx-auto" /></p>
<p>Once CodeGPT is installed, you should see a new CodeGPT icon in the editor’s sidebar. When you click on this, you’ll be taken to the CodeGPT interface. Click the dropdown menu at the top of this panel and select Ollama as the provider, and <code>codellama</code> as the model:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726171147953/b1d32f3a-e024-4325-9daf-8d0aa160fc47.png" alt class="image--center mx-auto" /></p>
<p>Once you’re up and running, you will see a text area at the bottom of this panel to start chatting. Try entering a prompt such as “Generate the code for a simple React component”.</p>
<p>Code Llama will start processing your request. Keep in mind that running a model locally is not as powerful, or fast, as an online service like Meta AI or ChatGPT. After a few seconds, you should have a result in the chat window.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726171287146/577825c9-e699-4df6-8fe4-c3f89e9504de.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-setting-up-completion">Setting up completion</h2>
<p>You can also use CodeGPT to suggest code completion, like GitHub Copilot and similar tools do. To set this up, in the CodeGPT Chat window, click the Menu button at the top left part of the screen. A menu will slide out with several options.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726171403849/787917d0-4413-4663-9e62-f8a585b56ad4.png" alt class="image--center mx-auto" /></p>
<p>Select “Autocomplete” to set up code completion.</p>
<p>Code Llama has a <code>code</code> variation that you can use for code completion. It is a separate model, so you’ll have to make another large download. Select the <code>codellama:code</code> model from the “AI Model” dropdown:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726171506603/d179d376-0e4a-4bdc-9bde-0ebaa0dada60.png" alt class="image--center mx-auto" /></p>
<p>Next, make sure to click the toggle switch to enable completion:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726171555493/75f284a1-b164-42b1-ade4-dc1f617319d5.png" alt class="image--center mx-auto" /></p>
<p>Now, as you type in your editor, Code Llama will make suggestions for you. For example, here it is filling in the <code>PropTypes</code> for a <code>Greeter</code> component:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726171695622/757a28da-dc0d-4118-bdaf-b8c584ee3632.png" alt class="image--center mx-auto" /></p>
<p>If you like a suggestion, you can press the Tab key to accept it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726171724789/11fabb93-b01f-4eae-926d-1a9980729185.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-have-fun">Have fun!</h2>
<p>That’s really all there is to it. You now have AI chat and code completion integrated in Visual Studio Code!</p>
]]></content:encoded></item><item><title><![CDATA[Fun with arrays]]></title><description><![CDATA[In this article, we'll look at some weird quirks with JavaScript arrays to learn a little more about how they work under the hood.
An array is a collection or list of values. It could hold just strings:
const names = ['Luke', 'Leia', 'Han'];

Or a mi...]]></description><link>https://joeattardi.dev/fun-with-arrays</link><guid isPermaLink="true">https://joeattardi.dev/fun-with-arrays</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Wed, 25 Oct 2023 19:03:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/UJN_XAg0ECI/upload/612c70bdb8ac05f2100a542b842201ab.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, we'll look at some weird quirks with JavaScript arrays to learn a little more about how they work under the hood.</p>
<p>An array is a collection or list of values. It could hold just strings:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> names = [<span class="hljs-string">'Luke'</span>, <span class="hljs-string">'Leia'</span>, <span class="hljs-string">'Han'</span>];
</code></pre>
<p>Or a mix of different types:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> stuff = [<span class="hljs-string">'Hello'</span>, <span class="hljs-number">42</span>, <span class="hljs-literal">true</span>, <span class="hljs-number">3.14</span>];
</code></pre>
<p>Arrays are cool because you can iterate over them with a <code>for</code> loop or one of the array utility functions like <code>forEach</code>, <code>map</code>, or <code>reduce</code>.</p>
<h2 id="heading-what-does-length-really-mean">What does <code>length</code> really mean?</h2>
<p>Let's start with a normal, everyday case. If you have an array, you can check its <code>length</code> property to see how many items are in the array:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> values = [<span class="hljs-string">'one'</span>, <span class="hljs-string">'two'</span>, <span class="hljs-string">'three'</span>];
<span class="hljs-built_in">console</span>.log(values.length);
</code></pre>
<p>The <code>console.log</code> above will print <code>3</code>, because there are three elements in the array.</p>
<p>What happens if you do this, though:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> names = [];
names[<span class="hljs-number">10</span>] = <span class="hljs-string">'Joe'</span>;
<span class="hljs-built_in">console</span>.log(names.length);
</code></pre>
<p>There's only one name in this array, but the console.log will print <code>11</code>.</p>
<p>Here's another one. You probably won't ever see this in real-world code, but it helps illustrate the point:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> names = [];
names[<span class="hljs-number">10</span>] = <span class="hljs-string">'Joe'</span>;

<span class="hljs-comment">// You'd never do this in real life</span>
names[<span class="hljs-number">12.5</span>] = <span class="hljs-string">'Bob'</span>;

<span class="hljs-built_in">console</span>.log(names.length);
</code></pre>
<p>What do you think will be printed now? If you guessed <code>11</code> again, you're correct. By now you can see that the <code>length</code> of an array actually does not indicate the <em>number of values</em> in the array.</p>
<p>If you check the value at <code>names[12.5]</code>, you'll see that Bob is, in fact, there:</p>
<pre><code class="lang-plaintext">console.log(names[12.5]); // 'Bob'
</code></pre>
<h3 id="heading-so-what-does-length-really-mean">So what does <code>length</code> really mean?</h3>
<p>The answer to this mystery lies in the <a target="_blank" href="https://tc39.es/ecma262/multipage/indexed-collections.html#sec-properties-of-array-instances-length">ECMAScript Language Specification</a>. It says:</p>
<blockquote>
<p>The "length" property of an Array instance is a data property whose value is always numerically greater than the name of every configurable own property whose name is an array index.</p>
</blockquote>
<p>So what constitutes an array index? In short, <a target="_blank" href="https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#array-index">the specification</a> says that it's an integer value.</p>
<p>That explains why, in the second example, setting <code>names[12.5]</code> to <code>Bob</code> did not affect the <code>length</code> property. <code>12.5</code> is not an integer value!</p>
<h2 id="heading-array-like-objects">Array-like objects</h2>
<p>JavaScript has a notion of <em>array-like objects</em>. These are objects that have properties indexed like an array, but aren't actually arrays. Array-like objects also have a <code>length</code> property.</p>
<p>Here's a contrived example of an array-like object:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> names = {
    <span class="hljs-number">0</span>: <span class="hljs-string">'Joe'</span>,
    <span class="hljs-number">1</span>: <span class="hljs-string">'Bob'</span>,
    <span class="hljs-number">2</span>: <span class="hljs-string">'Bill'</span>,
    <span class="hljs-attr">length</span>: <span class="hljs-number">3</span> <span class="hljs-comment">// don't forget the length!</span>
};
</code></pre>
<p>You can use an array-like object in a <code>for</code> loop:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; names.length; i++) {
  <span class="hljs-built_in">console</span>.log(names[i]);
}
</code></pre>
<p>That's cool, but you can do more. Because this object fulfills the contract of an array-like object, you can use array methods like <code>map</code> with a little JavaScript trickery:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> uppercaseNames = <span class="hljs-built_in">Array</span>.prototype.map.call(names, <span class="hljs-function"><span class="hljs-params">name</span> =&gt;</span> {
    name.toUpperCase());
});
</code></pre>
<p>In the above example, <code>uppercaseNames</code> will be an array (an actual array!) of the names uppercased: <code>['JOE', 'BOB', 'BILL']</code>.</p>
<p>This isn't too useful for a weird array-like object you constructed by hand, but it can come in handy when working with the DOM.</p>
<p>For example, consider the <code>document.querySelectorAll</code> method. You might think this returns an array, but it actually returns a <code>NodeList</code>. This is an array-like object. It even has a <code>forEach</code> method, but it's missing other array methods like <code>map</code> or <code>find</code>.</p>
<p>You could use <code>find</code> on a <code>NodeList</code> to search for a node that meets a certain condition. Or, maybe you want to use <code>map</code> to transform the nodes into an array of their attribute values.</p>
<h2 id="heading-the-incredible-shrinking-array">The incredible shrinking array</h2>
<p>I'll leave you with one last array trick. Did you know that you can change an array's <em>length</em> property? That's right, the property is writable.</p>
<p>If you set the <code>length</code> to a smaller value, any remaining elements are removed from the array:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> names = [<span class="hljs-string">'Joe'</span>, <span class="hljs-string">'Bob'</span>, <span class="hljs-string">'Bill'</span>];
names.length = <span class="hljs-number">1</span>;

<span class="hljs-built_in">console</span>.log(names); <span class="hljs-comment">// ['Joe']</span>
<span class="hljs-built_in">console</span>.log(names[<span class="hljs-number">1</span>]); <span class="hljs-comment">// undefined</span>
<span class="hljs-built_in">console</span>.log(names[<span class="hljs-number">2</span>]); <span class="hljs-comment">// undefined</span>
</code></pre>
<p>Not only does this change the length of the array, but it gets rid of the extra elements, too.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>If you've been working with JavaScript for any length of time, this array weirdness shouldn't surprise you. And if you are new to JavaScript (welcome!) consider this a sign of interesting things to come.</p>
<p>I hope you found this array trivia to be interesting, and maybe even a little useful!</p>
]]></content:encoded></item><item><title><![CDATA[Are Computer Science degrees still relevant?]]></title><description><![CDATA[I took a more traditional path into tech, going to a 4-year university and getting a Computer Science degree (way back in 2004!). These days, it's no secret that there are many alternate paths to a software development job. The three main paths today...]]></description><link>https://joeattardi.dev/are-computer-science-degrees-still-relevant</link><guid isPermaLink="true">https://joeattardi.dev/are-computer-science-degrees-still-relevant</guid><category><![CDATA[Computer Science]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Fri, 13 Oct 2023 19:26:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/2RouMSg9Rnw/upload/f1ceea5bf60bf7abd33bc6068c6d1627.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I took a more traditional path into tech, going to a 4-year university and getting a Computer Science degree (way back in 2004!). These days, it's no secret that there are many alternate paths to a software development job. The three main paths today are:</p>
<ol>
<li><p>Traditional CS education</p>
</li>
<li><p>Bootcamp</p>
</li>
<li><p>Completely self-taught</p>
</li>
</ol>
<p>I have seen people become very successful taking any of these 3 paths. It's clear that a CS degree is no longer necessary to get a good tech job. Does that mean they're no longer worth it?</p>
<h2 id="heading-what-i-learned-in-my-cs-program">What I learned in my CS program</h2>
<p>From 2000 to 2004, I went to <a target="_blank" href="https://www.uml.edu/Sciences/computer-science/default.aspx">UMass Lowell</a>. The curriculum started with the class Computing 1, which was a few hundred freshmen in a big lecture hall learning C programming. Computing 2 moved to object-oriented C++, and later courses covered databases, operating systems, and Java.</p>
<p>At my current position, I use none of the above in my day-to-day work. Today I work mostly with JavaScript, which I didn't learn at all during my college years. Every skill I use today was self-taught.</p>
<p>However, data structures and algorithms, the fundamentals of computer science, have stuck with me and helped me to solve problems all the time. Even these, of course, can be learned outside of a college environment.</p>
<h2 id="heading-back-to-the-question">Back to the question</h2>
<p>So, back to the question: are CS degrees still relevant? Well, I would say while they are in no way a prerequisite to being successful in this field, there is still a lot of benefit.</p>
<p>Of the three paths above, most people I have worked with (and myself as well) have followed a hybrid path combining two or more. In my case, it's a hybrid of a CS foundation with self-taught knowledge.</p>
<p>I have also worked with talented engineers who started with a bootcamp and are still on their learning journey, who are progressing all the time.</p>
<h2 id="heading-the-most-critical-skill">The most critical skill</h2>
<p>Whatever path you choose for your adventure, the most critical skill to learn is <em>how to learn effectively</em>. This isn't the same for everyone - what helps me learn effectively may differ from what works for you.</p>
<p>The other important things to consider are <em>what</em> to learn and <em>why</em>. Don't just learn programming languages for the sake of learning more. Over the past 20 years, I have learned:</p>
<ul>
<li><p>Python</p>
</li>
<li><p>Ruby</p>
</li>
<li><p>PHP</p>
</li>
<li><p>C</p>
</li>
<li><p>C++</p>
</li>
<li><p>Elixir</p>
</li>
<li><p>Java</p>
</li>
<li><p>JavaScript</p>
</li>
<li><p>TypeScript</p>
</li>
</ul>
<p>Of those, I only really know the last three today. I learned those other languages for the sake of learning them, thinking it would help me get ahead. But if you don't have a good reason for learning something, you won't use that knowledge and like an old cache entry, you'll lose it.</p>
<p>I have, pretty much, forgotten everything about Python, Ruby, PHP, and Elixir. C and C++ are a distant memory, and since I went to a JavaScript-only job in 2015, I'm starting to forget Java as well.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>For me, a CS degree was a good path. Of course, this was in the early 2000s at a state school, at a time when college was much less expensive than it is now.</p>
<p>The bottom line is that you can follow any of the three paths, or a combination of them, to achieve success in a software development career.</p>
<p>So, yes, a CS degree is still relevant, but in my view it's not a must-have anymore.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding color contrast for accessibility]]></title><description><![CDATA[Accessibility is a popular topic these days - as it should be. There are many benefits of making your application accessible - it promotes inclusivity by making your app usable by everyone.
There are many aspects of accessibility that you need to kee...]]></description><link>https://joeattardi.dev/understanding-color-contrast-for-accessibility</link><guid isPermaLink="true">https://joeattardi.dev/understanding-color-contrast-for-accessibility</guid><category><![CDATA[Accessibility]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Fri, 06 Oct 2023 14:33:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9IBqihqhuHc/upload/1f7e1bc4e8ede18d81f1ac02c3de7a61.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Accessibility is a popular topic these days - as it should be. There are many benefits of making your application accessible - it promotes inclusivity by making your app usable by everyone.</p>
<p>There are many aspects of accessibility that you need to keep in mind, one of which is color contrast. Proper color contrast not only looks good, but it's critical for users with low vision.</p>
<p>Specifically, you need to make sure that there is enough contrast between your background color and text color. If the contrast is too low, the text is not easily distinguishable from the background and it's hard to read. Even for users without disabilities, this is problematic as it can lead to eye strain.</p>
<p>The Web Content Accessibility Guidelines (WCAG) provides some guidance on contrast ratios.</p>
<h2 id="heading-what-is-a-contrast-ratio">What is a contrast ratio?</h2>
<p>The term "contrast ratio" refers to the difference, or ratio, in brightness between the background and text colors.</p>
<p>The <a target="_blank" href="https://www.w3.org/TR/WCAG21/">WCAG guidelines</a> formally define the <a target="_blank" href="https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio">contrast ratio</a> as:</p>
<blockquote>
<p>(L1 + 0.05) / (L2 + 0.05), where</p>
<ul>
<li><p>L1 is the relative luminance of the lighter of the colors, and</p>
</li>
<li><p>L2 is the relative luminance of the darker of the colors.</p>
</li>
</ul>
</blockquote>
<h2 id="heading-how-much-contrast-is-enough">How much contrast is enough?</h2>
<p>The contrast ratios required by WCAG differ slightly depending on the size of the text.</p>
<h3 id="heading-large-text">Large text</h3>
<p>Large text size is defined as follows:</p>
<ul>
<li><p>For <strong>bold</strong> text, 14 points or larger</p>
</li>
<li><p>For non-bold text, 18 points or larger</p>
</li>
</ul>
<p>Large text has a more relaxed contrast requirement since larger text is easier to read. For large text, the minimum contrast ratio is 3:1. This minimum is known as Level AA.</p>
<p>There is also a notion of enhanced contrast, known as Level AAA. For large text, AAA requires a minimum ratio of 4.5:1.</p>
<h3 id="heading-normal-text">Normal text</h3>
<p>Since smaller text is not as easy to read, it has stricter contrast requirements.</p>
<p>For Level AA, text must have a minimum contrast ratio of 4.5:1. The enhanced Level AAA contrast is a minimum of 7:1.</p>
<h3 id="heading-non-text-elements">Non-text elements</h3>
<p>Non-text elements, such as icons, have a minimum contrast ratio of 3:1 for Level AA.</p>
<p>Level AAA does not define a minimum contrast for non-text elements.</p>
<p>The following table summarizes the different minimum contrast ratios:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td><strong>Large text</strong></td><td><strong>Normal text</strong></td><td><strong>Non-text</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>AA</strong></td><td>3:1</td><td>4.5:1</td><td>3:1</td></tr>
<tr>
<td><strong>AAA</strong></td><td>4.5:1</td><td>7:1</td></tr>
</tbody>
</table>
</div><h2 id="heading-checking-contrast">Checking contrast</h2>
<p>The easiest way to check your color contrast is to use a tool. WebAIM has an excellent [Contrast Checker](<a target="_blank" href="https://webaim.org/resources/contrastchecker/">https://webaim.org/resources/contrastchecker/</a>). You can enter your foreground and background colors, and it will show you if the contrast meets AA and AAA standards.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696601897431/92828ed8-b080-4961-b984-2491cf7f2c7c.png" alt="The WebAIM contrast checker tool" class="image--center mx-auto" /></p>
<p>The Chrome developer tools will also show the contrast ratio when inspecting an element:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696602264885/3720f172-ea7d-4a93-893f-db9e9da3ccda.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-visualizing-contrast">Visualizing contrast</h2>
<p>Here are a few examples of different color contrast ratios. Screenshots are courtesy of the <a target="_blank" href="https://webaim.org/resources/contrastchecker/">WebAIM Contrast Checker</a>.</p>
<p>1.4:1 (does not meet minimum standard):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696602339309/e20e8017-2cc4-4dba-946c-c28004cdf959.png" alt="A contrast ratio of 1.4:1" class="image--center mx-auto" /></p>
<p>4.51:1 (meets level AA standard):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696602406591/8aa1689e-4400-44bd-9e4d-a2971856e3c7.png" alt class="image--center mx-auto" /></p>
<p>7:1 (meets level AAA standard):</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696602428744/03e8d1d9-a0dc-4e02-b861-a56ceca66c8a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Using sufficient color contrast is good for everyone, but critical for accessibility. Of course, color alone is not enough to make an accessible experience. For other resources to make your UI accessible, check out:</p>
<ul>
<li><p><a target="_blank" href="https://www.w3.org/WAI/standards-guidelines/wcag/">WCAG 2 Overview</a> [w3.org]</p>
</li>
<li><p><a target="_blank" href="https://webaim.org/">WebAIM</a> [webaim.org]</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Understanding error handling in Promise chains]]></title><description><![CDATA[Promise chains
You can create a chain of Promises by returning new Promises from a then handler. Here's a simple example that chains 3 promises together:
Promise.resolve(1)
    .then(id => {
        console.log(`Success: ${id}`);
        return Promi...]]></description><link>https://joeattardi.dev/understanding-error-handling-in-promise-chains</link><guid isPermaLink="true">https://joeattardi.dev/understanding-error-handling-in-promise-chains</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[promises]]></category><category><![CDATA[error handling]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Fri, 07 Jul 2023 16:13:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/ipuiM-36tAg/upload/75d6892af6e51492a5438980b0d95628.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-promise-chains">Promise chains</h2>
<p>You can create a chain of <code>Promise</code>s by returning new <code>Promise</code>s from a <code>then</code> handler. Here's a simple example that chains 3 promises together:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">1</span>)
    .then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>`</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">2</span>);
    }).then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>`</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">3</span>);
    }).then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>. Done!`</span>);
    });
</code></pre>
<p>The output of this chain will be:</p>
<pre><code class="lang-plaintext">Success: 1
Success: 2
Success: 3. Done!
</code></pre>
<p>To handle any errors that may occur in the chain, you can add a call to <code>catch</code> at the end of the chain. If any of the <code>Promise</code>s are rejected, this <code>catch</code> handler will run, and the rest of the chain is skipped.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">1</span>)
    .then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>`</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-number">2</span>);
    }).then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>`</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">3</span>);
    }).then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>. Done!`</span>);
    }).catch(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Error: <span class="hljs-subst">${id}</span>`</span>);
    });
</code></pre>
<p>The output of this chain will be:</p>
<pre><code class="lang-plaintext">Success: 1
Error: 2
</code></pre>
<h2 id="heading-the-weird-parts">The weird parts</h2>
<p>If you add more <code>then</code> calls after the <code>catch</code>, they will run!</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">1</span>)
    .then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>`</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-number">2</span>);
    }).then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>`</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">3</span>);
    }).then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>. Done!`</span>);
    }).catch(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Error: <span class="hljs-subst">${id}</span>`</span>);
    }).then(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Another then!'</span>);
    });
</code></pre>
<p>You'll get this output:</p>
<pre><code class="lang-plaintext">Success: 1
Error: 2
Another then!
</code></pre>
<p>Why does the chain continue after the <code>catch</code>? As it turns out, you can return another <code>Promise</code> from a <code>catch</code> handler. Here, the <code>catch</code> handler just prints to the console. The handler function, then, returns <code>undefined</code>. This actually returns a new <code>Promise</code>, fulfilled with the value <code>undefined</code>. You can verify this by adding the <code>id</code> argument to the last <code>then</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">1</span>)
    .then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>`</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-number">2</span>);
    }).then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>`</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve(<span class="hljs-number">3</span>);
    }).then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>. Done!`</span>);
    }).catch(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Error: <span class="hljs-subst">${id}</span>`</span>);
    }).then(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Success: <span class="hljs-subst">${id}</span>`</span>);
    });
</code></pre>
<p>And the output:</p>
<pre><code class="lang-plaintext">Success: 1
Error: 2
Success: undefined
</code></pre>
<h3 id="heading-re-rejecting">Re-rejecting</h3>
<p>This is a contrived scenario, but consider a function that does some asynchronous work and returns a <code>Promise</code>. Maybe it's a function that wraps the Fetch API, to return the JSON content. It has a <code>catch</code> for centralized request error logging:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getJSON</span>(<span class="hljs-params">url</span>) </span>{
    <span class="hljs-keyword">return</span> fetch(url)
        .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
        .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Fetch error:'</span>, error));
}
</code></pre>
<p>What happens if there's an error with the Fetch call? Before reading this post, the result might surprise you!</p>
<pre><code class="lang-javascript">getJSON(<span class="hljs-string">'http://invalid.fake'</span>)
    .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Success!'</span>, data))
    .catch(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error!'</span>));
</code></pre>
<p>Logically you might expect that <code>Error!</code> will be printed. But what actually happens is that <code>getJSON</code> logs the Fetch error but returns a <em>fulfilled</em> <code>Promise</code>. Your <code>then</code> handler will be executed and print:</p>
<pre><code class="lang-plaintext">Success! undefined
</code></pre>
<p>In order to get the result you want, the <code>catch</code> handler inside <code>getJSON</code> has to return a <em>rejected</em> <code>Promise</code>. You have to "re-reject" it:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getJSON</span>(<span class="hljs-params">url</span>) </span>{
    <span class="hljs-keyword">return</span> fetch(url)
        .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
        .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Fetch error:'</span>, error);
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(error);
        });
}
</code></pre>
<p>You could also <code>throw</code> the error, which will implicitly return a rejected <code>Promise</code> as well:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getJSON</span>(<span class="hljs-params">url</span>) </span>{
    <span class="hljs-keyword">return</span> fetch(url)
        .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
        .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Fetch error:'</span>, error);
            <span class="hljs-keyword">throw</span> error;
        });
}
</code></pre>
<p>Either way, now when you call <code>getJSON</code> and an error occurs, it will correctly return a rejected <code>Promise</code>.</p>
<h2 id="heading-summary">Summary</h2>
<p><code>Promise</code> chains actually work a lot like <code>try</code>/<code>catch</code> blocks in JavaScript. If an exception is thrown within a <code>try</code> block, it jumps right to the <code>catch</code> block and skips the rest of the <code>try</code> - just like how <code>catch()</code> skips the rest of the <code>Promise</code> chain.</p>
<p>Also, if you have a function that catches an exception, you'll need to re-throw it if you want it to propagate back up to the calling function.</p>
]]></content:encoded></item><item><title><![CDATA[Customizing `JSON.parse` and `JSON.stringify`]]></title><description><![CDATA[The JSON.stringify and JSON.parse functions are handy for converting objects to JSON strings and back again.
However, not all properties of an object are serializable. Functions, regular expressions, and Date objects are all examples of values that c...]]></description><link>https://joeattardi.dev/customizing-jsonparse-and-jsonstringify</link><guid isPermaLink="true">https://joeattardi.dev/customizing-jsonparse-and-jsonstringify</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[json]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Thu, 27 Apr 2023 03:27:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/FkjaN-7gWC0/upload/a7598efb26469d37ae186592dd08e380.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <code>JSON.stringify</code> and <code>JSON.parse</code> functions are handy for converting objects to JSON strings and back again.</p>
<p>However, not all properties of an object are serializable. Functions, regular expressions, and <code>Date</code> objects are all examples of values that can't be translated to a string and back again.</p>
<p>Let's create a user object containing a <code>Date</code> property.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> user = {
    <span class="hljs-attr">username</span>: <span class="hljs-string">'admin'</span>,
    <span class="hljs-attr">lastLogin</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>()
};
</code></pre>
<p>When we stringify this object, the <code>Date</code> becomes an ISO date string:</p>
<pre><code class="lang-javascript">{
    <span class="hljs-string">"username"</span>: <span class="hljs-string">"admin"</span>,
    <span class="hljs-string">"lastLogin"</span>: <span class="hljs-string">"2023-04-27T01:46:16.100Z"</span>
}
</code></pre>
<p>This is a good string representation. The problem is when we pass this string to <code>JSON.parse</code>, the resulting object's <code>lastLogin</code> property will still be a string - it won't be turned back into a <code>Date</code>.</p>
<h2 id="heading-adding-a-reviver-function">Adding a reviver function</h2>
<p>We can provide customized deserialization logic with a <em>reviver</em> function. This is a function that's called during the parsing process. The reviver function takes two arguments: a key and a value. It's called for each key/value pair in the object. For each invocation of the reviver, the value returned for a given key is used as the final value in the parsed object.</p>
<p>Finally, the reviver function is then called with an empty key, and the parsed object as its value. This allows you to make any final changes to the object before returning it from <code>JSON.parse</code>.</p>
<p>We can write a reviver function to convert this JSON string back to the original user object, <code>Date</code> and all.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reviver</span>(<span class="hljs-params">key, value</span>) </span>{
    <span class="hljs-keyword">if</span> (key === <span class="hljs-string">'lastLogin'</span>) {
        <span class="hljs-comment">// pass the date string to the Date constructor</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(value);
    }
}

<span class="hljs-keyword">const</span> parsed = <span class="hljs-built_in">JSON</span>.parse(jsonString, reviver);
</code></pre>
<h2 id="heading-adding-a-replacer-function">Adding a replacer function</h2>
<p>What if we want to store the <code>lastLogin</code> date in a different format? Maybe instead of a human readable ISO string, we want to use a more compact timestamp format.</p>
<p>We can customize <code>JSON.stringify</code> by writing a replacer function. This function is similar to the reviver function for <code>JSON.parse</code>. It is called first with the object itself, then is called again for each key/value pair.</p>
<p>By the time it is called with the key/value pairs, the stringification of these properties has already been done. However, the original object can still be accessed via the <code>this</code> context (as long as it's not an arrow function!).</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">replacer</span>(<span class="hljs-params">key, value</span>) </span>{
    <span class="hljs-keyword">if</span> (key === <span class="hljs-string">'lastLogin'</span>) {
        <span class="hljs-comment">// value is already a string here, but we can access the </span>
        <span class="hljs-comment">// original property</span>
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.lastLogin.getTime();
    }

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

<span class="hljs-keyword">const</span> json = <span class="hljs-built_in">JSON</span>.stringify(user, replacer);
</code></pre>
<p>Now when we call <code>JSON.stringify</code> on the user, the <code>lastLogin</code> field will be a numeric timestamp.</p>
<h3 id="heading-alternative-use-a-tojson-function">Alternative: use a <code>toJSON</code> function</h3>
<p>If an object being stringified has a <code>toJSON</code> function, the stringification is done on the return value of that function rather than the original object.</p>
<p>With our user object, this might look like:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createUser</span>(<span class="hljs-params">name</span>) </span>{
    <span class="hljs-keyword">return</span> {
        name,
        <span class="hljs-attr">lastLogin</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(),
        toJSON() {
            <span class="hljs-keyword">return</span> {
                <span class="hljs-attr">name</span>: <span class="hljs-built_in">this</span>.name,
                <span class="hljs-attr">lastLogin</span>: <span class="hljs-built_in">this</span>.lastLogin.getTime()
            }  
        }
    }
}

<span class="hljs-built_in">JSON</span>.stringify(createUser(<span class="hljs-string">'admin'</span>));
</code></pre>
<p>When we call <code>JSON.stringify</code> our <code>toJSON</code> function is called, and the return value is used for stringification.</p>
<p>Using replacer and reviver functions gives us greater control over the serialization of objects to JSON, and lets us persist more complex objects in local storage.</p>
]]></content:encoded></item><item><title><![CDATA[How many ways can we reverse an Array?]]></title><description><![CDATA[There's a Stage 3 proposal to add several array methods including Array.prototype.toReversed, which will create a reversed copy of the array. This will be a welcome addition since Array.prototype.reverse mutates the array, which often is not what we ...]]></description><link>https://joeattardi.dev/how-many-ways-can-we-reverse-an-array</link><guid isPermaLink="true">https://joeattardi.dev/how-many-ways-can-we-reverse-an-array</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[array methods]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Wed, 23 Nov 2022 03:43:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669174975431/c-8s0_rcS.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There's a <a target="_blank" href="https://github.com/tc39/proposal-change-array-by-copy">Stage 3 proposal</a> to add several array methods including <code>Array.prototype.toReversed</code>, which will create a reversed <em>copy</em> of the array. This will be a welcome addition since <code>Array.prototype.reverse</code> mutates the array, which often is <em>not</em> what we want.</p>
<p>I thought it might be fun to explore some of the ways we can implement this new method using currently available language features. Of course, there is <a target="_blank" href="https://www.npmjs.com/package/array.prototype.toreversed">already a package on npm</a> that polyfills this function, so this is mostly an exercise for learning purposes only.</p>
<h2 id="heading-reversing-a-copy-of-the-array">Reversing a copy of the array</h2>
<p>The most straightforward way to do this is make a copy of the array, and then call <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse"><code>reverse</code></a> on it. This has the end result of not mutating the original array, but it does mutate the copy, so this is a bit of a cheat.</p>
<h3 id="heading-using-slice">Using <code>slice</code></h3>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice"><code>Array.prototype.slice</code></a> will create a shallow copy of the array. This means that the references to each array element is copied into a new array. Reversing this copy mutates the new array by reordering items, but won't affect the ordering of the original array, or modify any of its elements.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> reversed = originalArray.slice().reverse();
</code></pre>
<h3 id="heading-using-array-spread">Using array spread</h3>
<p>We can use the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax">spread</a> syntax to create a copy of the array, then reverse it.</p>
<p>This is essentially doing the same thing as the <code>slice</code> approach. Make sure the <code>.reverse</code> call is outside the brackets, otherwise we'll be mutating the array <em>then</em> copying it.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// ✅ Copies the array, then mutates the copy</span>
<span class="hljs-keyword">const</span> reversed = [...originalArray].reverse();

<span class="hljs-comment">// ❌ Mutates the original array, then copies</span>
<span class="hljs-keyword">const</span> reversed = [...originalArray.reverse()];
</code></pre>
<h2 id="heading-using-map">Using <code>map</code></h2>
<p>We can build the reversed array by mapping each element to the corresponding element at the other end of the array:</p>
<ul>
<li>element 0 becomes element <em>n - 1</em></li>
<li>element 1 becomes element <em>n - 2</em></li>
<li>etc.</li>
</ul>
<p>The new element is calculated by subtracting the current index from the last index. For this we can call <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map"><code>map</code></a> on the array:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> reversed = originalArray.map(<span class="hljs-function">(<span class="hljs-params">el, index</span>) =&gt;</span> 
  originalArray[originalArray.length - <span class="hljs-number">1</span> - index]
);
</code></pre>
<h2 id="heading-building-the-array-in-reverse-order">Building the array in reverse order</h2>
<p>This one, again, is a partial cheat if we want to avoid mutation since we are mutating the new array on each turn of the loop. In most cases, this is probably acceptable as long as the original array remains unchanged.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> reversed = [];
originalArray.forEach(<span class="hljs-function"><span class="hljs-params">el</span> =&gt;</span> reversed.unshift(el));
</code></pre>
<h2 id="heading-using-reduce">Using <code>reduce</code></h2>
<p>If we want to be purists and not mutate anything, we can use <code>reduce</code> to reverse the array. For small arrays it probably doesn't matter, but keep in mind that we are going to increase memory usage, since a new array is created each time through.</p>
<p>This is a good exercise for understanding how <code>reduce</code> works but probably not an ideal version to use in a production app.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> reversed = originalArray.reduce(<span class="hljs-function">(<span class="hljs-params">result, el</span>) =&gt;</span> [el, ...result], []);
</code></pre>
<p>We start with an empty array. For each element in the array, we create a new array with that element at the beginning, and spread the previous result, creating a new array. When the loop is complete, we'll have the new reversed array.</p>
<h2 id="heading-which-to-use">Which to use?</h2>
<p>For smaller arrays, analyzing differences between these approaches is probably an exercise in premature optimization. In such cases I usually prefer a more readable approach, such as the spread syntax:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> reversed = [...originalArray].reverse();
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Comparing `const` declarations and immutable objects]]></title><description><![CDATA[Way back in my Java days, when interviewing candidates, I would often ask the candidate to explain the meaning of the final keyword. Many times I would get an answer along the lines of "It's a constant value" or "It can't be changed once assigned".
F...]]></description><link>https://joeattardi.dev/comparing-const-declarations-and-immutable-objects</link><guid isPermaLink="true">https://joeattardi.dev/comparing-const-declarations-and-immutable-objects</guid><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Thu, 01 Sep 2022 04:55:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/Ff73ThfMLeM/upload/v1662008127545/Q9oVYD2-u.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Way back in my Java days, when interviewing candidates, I would often ask the candidate to explain the meaning of the <code>final</code> keyword. Many times I would get an answer along the lines of "It's a constant value" or "It can't be changed once assigned".</p>
<p>Fast forward to today, living in JavaScript Land, we now have <code>const</code> declarations. I ask the same question to JavaScript candidates and often get the same sorts of answers.</p>
<p>On the surface, these answers are more or less correct, but when I would ask follow-up questions about what exactly they meant by "constant" or "can't be changed", I was sometimes surprised by the answers I received. </p>
<p>This appears to be a question that can sometimes trip up beginners. Let's take a deeper look.</p>
<h1 id="heading-the-const-keyword">The <code>const</code> keyword</h1>
<p>Back in the dark ages, we had <code>var</code> for declaring variables and that was it! ES2015 gave us two new tools: <code>const</code> and <code>let</code>.</p>
<p>We use <code>const</code> like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> name = <span class="hljs-string">'Joe'</span>;
</code></pre>
<p>I have just declared <code>name</code>, which is a reference to the string <code>'Joe'</code>. If I try to assign a new value to <code>name</code>, I get an error:</p>
<pre><code class="lang-javascript">name = <span class="hljs-string">'Liz'</span>; <span class="hljs-comment">// TypeError: Assignment to constant variable.</span>
</code></pre>
<p>Great, so this is a <em>const</em>ant value! I can't change the name assigned to <code>name</code>. This much, I think, is pretty clear.</p>
<h2 id="heading-what-about-an-array">What about an array?</h2>
<p>A string is a primitive value. What if I use <code>const</code> for, say, an array?</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> foods = [<span class="hljs-string">'apple'</span>, <span class="hljs-string">'banana'</span>, <span class="hljs-string">'pear'</span>];
</code></pre>
<p>Indeed, I can't set a new array:</p>
<pre><code class="lang-javascript">foods = [<span class="hljs-string">'bacon'</span>, <span class="hljs-string">'chicken'</span>, <span class="hljs-string">'turkey'</span>]; <span class="hljs-comment">// TypeError: Assignment to constant variable.</span>
</code></pre>
<p>I want to take <code>banana</code> out of my array. I might try to do that with <code>Array.prototype.filter</code>, but I run into the same problem:</p>
<pre><code class="lang-javascript">foods = foods.filter(<span class="hljs-function"><span class="hljs-params">food</span> =&gt;</span> food !== <span class="hljs-string">'banana'</span>); <span class="hljs-comment">// TypeError: Assignment to constant variable.</span>
</code></pre>
<p>That won't work because <code>foods</code> is declared with <code>const</code>. Of course, this will work fine if I assign the result of <code>foods.filter</code> to another variable name, but let's pretend that for whatever reason the array referenced by <code>foods</code> has to have the banana-less array.</p>
<p>Instead of filtering, a value can also be removed from an array with <code>Array.prototype.splice</code>. But since <code>foods</code> is a constant that can't be changed, this will fail as well, right?</p>
<pre><code class="lang-javascript">foods.splice(foods.indexOf(<span class="hljs-string">'banana'</span>), <span class="hljs-number">1</span>); <span class="hljs-comment">// No error!</span>
<span class="hljs-built_in">console</span>.log(foods); <span class="hljs-comment">// ['apple', 'pear']</span>
</code></pre>
<p>This works! The array referenced by <code>foods</code> no longer contains <code>banana</code>. Why did this work if we used <code>const</code>?</p>
<h2 id="heading-the-reference-is-the-constant">The <em>reference</em> is the constant!</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1662005194230/4c8iKmsjW.gif" alt="Obi-Wan breaks the news" /></p>
<p>As it turns out, the <em>const</em>ant is the <em>reference</em> itself, not the value it's pointing to. We can do anything we want to the <code>foods</code> array as long as we don't try to reassign a new value to <code>foods</code>.</p>
<p>So you see, explaining <code>const</code> by saying "it's a constant value" or "it can't be changed" is only true from a certain point of view.</p>
<h1 id="heading-immutable-data">Immutable data</h1>
<p>What if we really, truly, want to lock down the <code>foods</code> array so we can't modify it? The reason we can still get away with this is because functions like <code>Array.prototype.splice</code> <em>mutate</em> the thing. This is just a fancy way of saying we are modifying its internal state.</p>
<p>Some values, like strings, are <em>immutable</em>, so for a string, our simplified explanation of <code>const</code> is accurate. But for objects and arrays, we still have a mutation escape hatch.</p>
<p>It's actually easy to achieve immutability for our humble array of foods. We can <em>freeze</em> it! </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> foods = [<span class="hljs-string">'apple'</span>, <span class="hljs-string">'banana'</span>, <span class="hljs-string">'pear'</span>]; <span class="hljs-comment">// At this point we can still mutate the array</span>
<span class="hljs-built_in">Object</span>.freeze(foods); <span class="hljs-comment">// Not anymore!</span>
</code></pre>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze"><code>Object.freeze</code></a> essentially locks down our array. We can't do anything to it now:</p>
<pre><code class="lang-javascript">foods.splice(foods.indexOf(<span class="hljs-string">'banana'</span>), <span class="hljs-number">1</span>); <span class="hljs-comment">// TypeError: Cannot delete property '2' of [object Array]</span>

foods.push(<span class="hljs-string">'bacon'</span>); <span class="hljs-comment">// TypeError: Cannot add property 3, object is not extensible</span>
</code></pre>
<p>Now our <code>foods</code> array is untouchable. Like before, we can still <code>filter</code> it as long as we assign it to a new name. Interestingly, the new filtered array is no longer frozen:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> noBananas = foods.filter(<span class="hljs-function"><span class="hljs-params">food</span> =&gt;</span> food !== <span class="hljs-string">'banana'</span>);
noBananas.push(<span class="hljs-string">'bacon'</span>); <span class="hljs-comment">// No error!</span>
<span class="hljs-built_in">console</span>.log(noBananas); <span class="hljs-comment">// ['apple', 'pear', 'bacon'];</span>
</code></pre>
<h3 id="heading-a-note-on-objectfreeze">A note on <code>Object.freeze</code></h3>
<p>You may notice that the array threw exceptions when trying to add or remove elements after it was frozen. As we will see soon, this does not happen with other objects (unless in <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode">strict mode</a>). When not running in strict mode, the mutation will fail silently.</p>
<h2 id="heading-freezing-objects">Freezing objects</h2>
<p>Let's take one more example, an array of users, and freeze it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> users = [
  { <span class="hljs-attr">username</span>: <span class="hljs-string">'obiwan'</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">'kenobi@gmail.com'</span> },
  { <span class="hljs-attr">username</span>: <span class="hljs-string">'yoda'</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">'yoda@coruscant.com'</span> }
];

<span class="hljs-built_in">Object</span>.freeze(users);

<span class="hljs-comment">// This will fail with TypeError: Cannot add property 2, object is not extensible</span>
users.push({ <span class="hljs-attr">username</span>: <span class="hljs-string">'chewbacca'</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">'chewie@kashyykmail.com'</span> });
</code></pre>
<p><img src="https://media.giphy.com/media/l3fZQ3Zs6tVaKpwVq/giphy.gif" alt="Ben Kenobi?" /></p>
<p>To protect his identity, let's change Obi-Wan's username to <code>ben</code> (the Empire will surely think the last name is a coincidence):</p>
<pre><code class="lang-javascript">users[<span class="hljs-number">0</span>].username = <span class="hljs-string">'ben'</span>;
<span class="hljs-built_in">console</span>.log(users[<span class="hljs-number">0</span>]); <span class="hljs-comment">// { username: 'ben', email: 'kenobi@gmail.com' }</span>
</code></pre>
<p>No error was thrown, and when we check the user object, it was updated (so it did not fail silently as we discussed above!)</p>
<p>What happened? Isn't the array frozen? Indeed it is, the individual items in the array are not. To achieve this, we need to freeze every item in the array:</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">const</span> users = [
    { <span class="hljs-attr">username</span>: <span class="hljs-string">'obiwan'</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">'kenobi@gmail.com'</span> },
    { <span class="hljs-attr">username</span>: <span class="hljs-string">'yoda'</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">'yoda@coruscant.com'</span> }
  ];

<span class="hljs-built_in">Object</span>.freeze(users);
users.forEach(<span class="hljs-function"><span class="hljs-params">user</span> =&gt;</span> <span class="hljs-built_in">Object</span>.freeze(user));

<span class="hljs-comment">// Change Obi-Wan's name.</span>
users[<span class="hljs-number">0</span>].username = <span class="hljs-string">'ben'</span>;

<span class="hljs-comment">// No error, let's check the object</span>
<span class="hljs-built_in">console</span>.log(users[<span class="hljs-number">0</span>]); <span class="hljs-comment">// { username: 'obiwan', email: 'kenobi@gmail.com' }</span>
</code></pre>
<p>Now that we've frozen each object in the array, we get the desired outcome. Array items can't be added, removed, or modified.</p>
<p>If we ran the same above code in strict mode, it would fail with an error:</p>
<pre><code>TypeError: Cannot assign <span class="hljs-keyword">to</span> <span class="hljs-keyword">read</span> <span class="hljs-keyword">only</span> property <span class="hljs-string">'username'</span> <span class="hljs-keyword">of</span> <span class="hljs-keyword">object</span> <span class="hljs-string">'#&lt;Object&gt;'</span>
</code></pre><h2 id="heading-recursively-freezing-objects">Recursively freezing objects</h2>
<p>At any given level, <code>Object.freeze</code> will only freeze the top-level properties. For deeply nested objects, you will need to traverse all the way down and freeze at each level.</p>
<p>Fortunately, there is a simple package called <a target="_blank" href="https://www.npmjs.com/package/deep-freeze"><code>deep-freeze</code></a> that will do this in a single function call:</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">import</span> deepFreeze <span class="hljs-keyword">from</span> <span class="hljs-string">'deep-freeze'</span>;

<span class="hljs-keyword">const</span> users = [
  { <span class="hljs-attr">username</span>: <span class="hljs-string">'obiwan'</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">'kenobi@gmail.com'</span> },
  { <span class="hljs-attr">username</span>: <span class="hljs-string">'yoda'</span>, <span class="hljs-attr">email</span>: <span class="hljs-string">'yoda@coruscant.com'</span> }
];

deepFreeze(users);
</code></pre>
<p>This will freeze the array as well as all the objects in it. If those objects had nested object properties, those would be frozen as well. Since we are in an ES module (we're using <code>import</code>), this automatically puts us in strict mode, so attempting to change Obi-Wan's username will throw an error.</p>
<h1 id="heading-summary">Summary</h1>
<ul>
<li><code>const</code> marks a <em>reference</em> as constant; it cannot be reassigned. However, the object pointed to by the <code>const</code> can be mutated.</li>
<li>To make an object truly unmodifiable, you will need to freeze it. </li>
<li><code>Object.freeze</code> does not recurse into nested properties, but the <a target="_blank" href="https://www.npmjs.com/package/deep-freeze"><code>deep-freeze</code></a> package will.</li>
</ul>
<p>Now you can crush this question on your next job interview!</p>
]]></content:encoded></item><item><title><![CDATA[Promise Tips: When do I need to create my own Promise instance?]]></title><description><![CDATA[Promises are pretty ubiquitous these days, but sometimes Promise based code is more complex that it needs to be.
Consider this getUserDetails function:
function getUserDetails(userId) {
  return new Promise((resolve, reject) => {
    fetch(`/users/${...]]></description><link>https://joeattardi.dev/promise-tips-when-do-i-need-to-create-my-own-promise-instance</link><guid isPermaLink="true">https://joeattardi.dev/promise-tips-when-do-i-need-to-create-my-own-promise-instance</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[promises]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Fri, 28 Jan 2022 16:07:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1643385990859/spgopLvxzu.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Promises are pretty ubiquitous these days, but sometimes <code>Promise</code> based code is more complex that it needs to be.</p>
<p>Consider this <code>getUserDetails</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserDetails</span>(<span class="hljs-params">userId</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    fetch(<span class="hljs-string">`/users/<span class="hljs-subst">${userId}</span>/details`</span>)
      .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
      .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> resolve(data));
      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> reject(error));
  });
}
</code></pre>
<p>This function returns a <code>Promise</code> that will be resolved when the fetch call is complete and the JSON response is received. </p>
<p>We make the <code>fetch</code> call and extract the JSON in the first <code>then</code> handler. <code>response.json()</code> also returns a <code>Promise</code>, so we call <code>then</code> on that too. Once we have the JSON result, we can resolve our returned <code>Promise</code>.</p>
<p>If there is an error, we reject our returned <code>Promise</code>.</p>
<p>Here's a somewhat rough analogy, but bear with me here. Suppose you want to buy an item listed on eBay. The above code is sort of like if you purchased the item, and the seller shipped it to eBay. Then, once eBay received it, they shipped it to you. Sounds overly complicated, right?</p>
<p>Client code that calls <code>getUserDetails</code> looks like this:</p>
<pre><code class="lang-javascript">getUserDetails(userId).then(<span class="hljs-function"><span class="hljs-params">details</span> =&gt;</span> {
  doSomethingWith(details);
});
</code></pre>
<p>We are calling <code>then</code> on the outer <code>Promise</code> that was returned from <code>getUserDetails</code>.</p>
<p>We can do better! If the asynchronous thing you are doing already returns a <code>Promise</code>, as <code>fetch</code> does, you <em>don't need to wrap it in your own <code>Promise</code></em>.</p>
<p>The above function can be written much more simply:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserDetails</span>(<span class="hljs-params">userId</span>) </span>{
  <span class="hljs-keyword">return</span> fetch(<span class="hljs-string">`/users/<span class="hljs-subst">${userId}</span>/details`</span>)
    .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json());
}
</code></pre>
<p>This function has the same net result! In both listings above, <code>getUserDetails</code> returns a <code>Promise</code> that resolves to the user details object.</p>
<p>To return to the eBay analogy: This approach is how eBay actually works: you purchase the item through eBay, eBay tells the seller, and the seller ships directly to you.</p>
<p>In the first example, we are creating our own <code>Promise</code> which wraps the asynchronous operation. The difference with the second example is that we are just returning the <code>Promise</code> that <code>response.json()</code> gives us.</p>
<h1 id="heading-when-would-i-want-to-create-my-own-promise">When would I want to create my own <code>Promise</code>?</h1>
<p>There are some cases where rolling your own <code>Promise</code> is unavoidable, for example when working with a callback or event based API.</p>
<h2 id="heading-event-based-apis">Event based APIs</h2>
<p>Let's make a quick and dirty image loader! This function will take an image URL and return an <code>img</code> element, but <em>not until the image has loaded</em>. </p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loadImage</span>(<span class="hljs-params">url</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> image = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'img'</span>);

    image.addEventListener(<span class="hljs-string">'load'</span>, <span class="hljs-function">() =&gt;</span> {
      resolve(image);
    });

    image.addEventListener(<span class="hljs-string">'error'</span>, <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
      reject(error);
    });

    image.src = url;
  });
}
</code></pre>
<p>Because the image element doesn't provide a <code>Promise</code> itself, in this case we have to roll our own. Depending on which event listener is fired, we either resolve the <code>Promise</code> with the now fully loaded image, or reject it with the error encountered while loading.</p>
<p>This is easy to use:</p>
<pre><code class="lang-javascript">loadImage(<span class="hljs-string">'/logo.png'</span>).then(<span class="hljs-function"><span class="hljs-params">image</span> =&gt;</span> container.appendChild(image));
</code></pre>
<h2 id="heading-callback-based-apis">Callback based APIs</h2>
<p>Some older APIs are still callback based. You might want to make a "promisified" version of such an API. For this, you will need to create a <code>Promise</code>.</p>
<p>Consider this simplified example of an API. It follows the typical Node.js callback pattern - it takes two callback function arguments. The first will be called if there is an error, and the second will be called on success. We use such an API like this:</p>
<pre><code class="lang-javascript">db.findItem(<span class="hljs-number">123</span>, <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'oops, an error:'</span>, error);
}, <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'got data:'</span>, data);
});
</code></pre>
<p>Callbacks can be a little painful to work with, so we can wrap this API with a <code>Promise</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findItemPromise</span>(<span class="hljs-params">recordId</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    db.findItem(recordId, <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> reject(error), <span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> resolve(data));
  });
}
</code></pre>
<p>This can actually be simplified a bit more. Since the <code>resolve</code> and <code>reject</code> handlers take a single argument, which matches the arguments of the <code>error</code> and <code>data</code> callbacks, we can just specify those functions themselves as the callbacks:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findItemPromise</span>(<span class="hljs-params">recordId</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
      db.findItem(recordId, reject, resolve);
    });
}
</code></pre>
<p>Now we can use the <code>findItemPromise</code> API:</p>
<pre><code class="lang-javascript">findItemPromise(recordId)
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'got data:'</span>, data))
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'oops, an error:'</span>, error));
</code></pre>
<p>In fact, if you are working with Node.js, you don't need to do this wrapping yourself. The Node.js API includes a <a target="_blank" href="https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original"><code>promisify</code></a> utility function that does exactly this!</p>
<h1 id="heading-summary">Summary</h1>
<ul>
<li>If the async API you are working with already returns a <code>Promise</code>, you most likely don't need to wrap it in your own new <code>Promise</code>. Instead, you can just utilize the existing <code>Promise</code>.</li>
<li>For event and callback based APIs, you will need to create your own <code>Promise</code> which wraps the API call, and calls the <code>resolve</code> and <code>reject</code> handlers accordingly.</li>
<li>Node.js has a <code>promisify</code> utility function that will convert any callback-based function (that follows the Node convention of (error, success) callbacks) into a <code>Promise</code> based one.</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Comparison of JavaScript modules]]></title><description><![CDATA[JavaScript has been around since 1995. In that time there have been several different ways to create modules. Due to browser compatibility issues and legacy codebases, all of these module types are still in use today.
What is a module?
A module is so...]]></description><link>https://joeattardi.dev/comparison-of-javascript-modules</link><guid isPermaLink="true">https://joeattardi.dev/comparison-of-javascript-modules</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[javascript modules]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Sun, 29 Nov 2020 22:23:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1606688625705/ZmVSCdrmy.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>JavaScript has been around since 1995. In that time there have been several different ways to create modules. Due to browser compatibility issues and legacy codebases, all of these module types are still in use today.</p>
<h1 id="what-is-a-module">What is a module?</h1>
<p>A module is some piece of functionality that is nicely encapsulated. A module defines a public API that is accessible from any code that uses the module. In addition, the module has some private, internal state that is <em>not</em> accessible from outside of the module.</p>
<p>This means that we just need to interact with the module's public API. We don't need to know about how the module is implemented under the hood.</p>
<p>Modules can also have dependencies on other modules.</p>
<h1 id="the-example-module">The example module</h1>
<p>For each module type, we'll look at the same module implemented in different ways. This is, simply, a counter module. The public API consists of three functions:</p>
<ul>
<li><code>increment</code>: Increments the counter</li>
<li><code>decrement</code>: Decrements the counter</li>
<li><code>getValue</code>: Gets the counter's current value</li>
</ul>
<p>Note that the counter itself is not publicly accessible. It can only be manipulated by calling the <code>increment</code> and <code>decrement</code> functions.</p>
<h1 id="module-types">Module types</h1>
<p>Let's take a look now at the different types of modules used in JavaScript applications.</p>
<h2 id="the-revealing-module-pattern">The "Revealing Module" pattern</h2>
<p>This is the oldest module type in use today. JavaScript had no language support for modules, so this pattern relies on a function's scope to provide the private state only accessible from inside the module. These types of modules are typically initialized with an immediately invoked function expression (IIFE). This is, essentially, a function that immediately calls itself.</p>
<p>The return value of the IIFE call is usually assigned to a variable, or a global variable on the browser's <code>window</code> object. Inside the IIFE call, the module's internals are set up, and an object is returned containing the module's public API.</p>
<p>Here's what the counter module looks like as a revealing module:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Counter = (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> value = <span class="hljs-number">0</span>;

  <span class="hljs-keyword">return</span> {
    increment() {
      value++;
    },

    decrement() {
      value--;
    },

    getValue() {
      <span class="hljs-keyword">return</span> value;
    }
  }
})();
</code></pre>
<p>The counter variable itself is defined inside the function, therefore it is not accessible outside of the module. We return an object containing the three functions of the public API.</p>
<p>We would use this module as follows:</p>
<pre><code class="lang-javascript">Counter.increment();
Counter.increment();
<span class="hljs-built_in">console</span>.log(Counter.getValue());
</code></pre>
<h2 id="asynchronous-module-definition-amd-modules">Asynchronous Module Definition (AMD) modules</h2>
<p>AMD modules are most commonly used with tools such as RequireJS. Its name comes from the fact that modules are loaded asynchronously. </p>
<p>An AMD module is defined with a call to a function called <code>define</code>. The first argument to <code>define</code> is an array of other module names that the module depends on. The second is a function that takes the dependencies as arguments. The return value of this function is the module's public API.</p>
<p>Here is an example of an AMD module with dependencies on jQuery and Lodash:</p>
<pre><code class="lang-javascript">define([<span class="hljs-string">'jquery'</span>, <span class="hljs-string">'lodash'</span>], <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$, _</span>) </span>{
  <span class="hljs-comment">// jQuery and Lodash can be accessed here</span>
  <span class="hljs-comment">// via the `$` and `_` arguments to the function</span>
}
</code></pre>
<p>If an AMD module has no dependencies, the dependency array argument can be omitted.</p>
<p>Here is our counter defined as an AMD module:</p>
<pre><code class="lang-javascript">define(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> value = <span class="hljs-number">0</span>;

  <span class="hljs-keyword">return</span> {
    increment() {
      value++;
    },

    decrement() {
      value--;
    },

    getValue() {
      <span class="hljs-keyword">return</span> value;
    }
  }
});
</code></pre>
<p>We would use our counter module from another AMD module like this.</p>
<pre><code class="lang-javascript">define([<span class="hljs-string">'./counter'</span>], <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">counter</span>) </span>{
  counter.increment();
  <span class="hljs-built_in">console</span>.log(counter.getValue());
});
</code></pre>
<h2 id="commonjs-modules">CommonJS modules</h2>
<p>CommonJS modules are typically used with Node.js. Each file is considered a module. To use functionality from another module, it is added to the current module by calling <code>require</code>, passing the module name. The module name can either be the relative path to another JavaScript file, or can be the name of a module installed from npm.</p>
<p>A CommonJS module's public API is declared by setting the <code>module.exports</code> property. Whatever is assigned to this will be the value returned when another module <code>require</code>s the module. There is an alternate syntax as well. CommonJS also exposes an <code>exports</code> property. Data and functions can be set on that property as well to define the module's public API.</p>
<p>That is, the following two are equivalent:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
  functionOne() { },
  functionTwo() { }
};

<span class="hljs-built_in">exports</span>.functionOne = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ };
<span class="hljs-built_in">exports</span>.functionTwo = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ };
</code></pre>
<p>Here is our counter module implemented as a CommonJS module:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> value = <span class="hljs-number">0</span>;

<span class="hljs-built_in">module</span>.exports = {
  increment() {
    value++;
  },

  decrement() {
    value--;
  },

  getValue() {
    <span class="hljs-keyword">return</span> value;
  }
};
</code></pre>
<p>The counter module can be used from another module by requiring it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> counter = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./counter'</span>);

counter.increment();
<span class="hljs-built_in">console</span>.log(counter.getValue());
</code></pre>
<h2 id="universal-module-definition-umd-modules">Universal Module Definition (UMD) modules</h2>
<p>UMD modules are a kind of "catch-all" module. A UMD module will attempt to detect what kind of environment it's running in. The exact code varies from module to module, but the general steps are:</p>
<ul>
<li>The module itself is defined in a factory function which returns the module's public API.</li>
<li>Check if we are running in an AMD environment, i.e. if <code>define</code> is defined and is a function. If so, call <code>define</code> and register the module, declaring its dependencies and passing the factory function.</li>
<li>Check for the presence of an <code>exports</code> property. If it exists, we are probably running in a CommonJS environment. The factory function is called, and <code>module.exports</code> is set to the return value.</li>
<li><p>Otherwise, call the factory function and assign its return value to the global scope.</p>
<p>We can define our counter module as a UMD module by using the following rough code, adapted from David Calhoun's excellent <a target="_blank" href="https://www.davidbcalhoun.com/2014/what-is-amd-commonjs-and-umd/">blog post</a>:</p>
</li>
</ul>
<pre><code class="lang-javascript">(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">root, factory</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> define === <span class="hljs-string">'function'</span> &amp;&amp; define.amd) {
    <span class="hljs-comment">// We're running in AMD</span>
    define(factory);
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">exports</span> === <span class="hljs-string">'object'</span>) {
    <span class="hljs-comment">// We're running in CommonJS</span>
    <span class="hljs-built_in">module</span>.exports = factory();
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Just set a property on the global object</span>
      root.Counter = factory();
  }
})(<span class="hljs-built_in">this</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> value = <span class="hljs-number">0</span>;

    <span class="hljs-keyword">return</span> {
        increment() {
            value++;
        },

        decrement() {
            value--;
        },

        getValue() {
            <span class="hljs-keyword">return</span> value;
        }
    };
}));
</code></pre>
<p>By using the UMD format, a module can have wide support across different modules and applications.</p>
<h2 id="ecmascript-es-modules">ECMAScript (ES) modules</h2>
<p>ES modules are the new standard, introduced in ES2015 (otherwise known as ES6). They introduce the <code>import</code> and <code>export</code> keywords to JavaScript language. </p>
<p>An ES module can have one <em>default export</em> and one or more <em>named exports</em>. The only real difference between these is the syntax to import them.</p>
<h3 id="default-export">Default export</h3>
<p>The default export is set by using the <code>export default</code> keyword. This can be an object, function, or even a single value. A module can only have one default export, but it isn't required. A default export is not bound to a name. A name is chosen for it when it is imported from another module (see below). </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">add</span>(<span class="hljs-params"></span>) </span>{
  ...
}
</code></pre>
<h3 id="named-exports">Named exports</h3>
<p>Named exports are bound to a name, but this name can be aliased when imported from another module. A named export is created by simply placing the <code>export</code> keyword in front of an object, function, or value. </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> pi = <span class="hljs-number">3.14</span>;
</code></pre>
<h3 id="importing">Importing</h3>
<p>A module is used by importing its default export or named exports. </p>
<p>When importing the default export, you assign it any name you want. Here's an example of the syntax:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> add <span class="hljs-keyword">from</span> <span class="hljs-string">'./addModule'</span>;
</code></pre>
<p>To import a named export, the syntax is slightly different:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { pi } <span class="hljs-keyword">from</span> <span class="hljs-string">'./math'</span>;
</code></pre>
<p>You can alias the named export:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { pi <span class="hljs-keyword">as</span> piValue } <span class="hljs-keyword">from</span> <span class="hljs-string">'./math'</span>;
</code></pre>
<p>In the above example, the <code>pi</code> named export will be bound to the name <code>piValue</code>. </p>
<p>You can also import multiple named exports, which can be a mix of objects, functions, and values:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { pi, squareRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">'./math'</span>;

<span class="hljs-built_in">console</span>.log(pi);
<span class="hljs-built_in">console</span>.log(squareRoot(<span class="hljs-number">9</span>));
</code></pre>
<p>Lastly, you can import all named exports together under a namespace:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> math <span class="hljs-keyword">from</span> <span class="hljs-string">'./math'</span>;
</code></pre>
<h3 id="the-counter-module">The counter module</h3>
<p>For completeness's sake, here is the counter as an ES module:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> value = <span class="hljs-number">0</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">increment</span>(<span class="hljs-params"></span>) </span>{
  value++;
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">decrement</span>(<span class="hljs-params"></span>) </span>{
  value++;
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getValue</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> value;
}
</code></pre>
<p>The module is used as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { increment, getValue } <span class="hljs-keyword">from</span> <span class="hljs-string">'./counter'</span>;

increment();
<span class="hljs-built_in">console</span>.log(getValue());
</code></pre>
<h1 id="compatibility">Compatibility</h1>
<p>Because AMD, CommonJS, UMD, and IIFE modules are all based on functions, they have very wide support. With the right tools they can be used with any runtime or browser. </p>
<p>Because ES modules involve the addition of new keywords, they aren't as widely supported. All modern browsers support ES modules natively, but they are not supported at all in Internet Explorer.</p>
<p>Fortunately, with tools like Babel or TypeScript, you can use the ES module syntax and the code will be transpiled into a form the browser will understand. </p>
<h1 id="summary">Summary</h1>
<p>In this article, we looked at several types of JavaScript modules:</p>
<ul>
<li>IIFE/Revealing Module</li>
<li>AMD</li>
<li>CommonJS</li>
<li>UMD</li>
<li>ES Module</li>
</ul>
<p>They all have pros and cons so make sure to choose what makes the most sense for your project. </p>
<p>That said, for greenfield projects you should probably be using ES modules as that is where things are going. </p>
<p>I hope you found this helpful!</p>
]]></content:encoded></item><item><title><![CDATA[Using Animations with Tailwind CSS]]></title><description><![CDATA[Tailwind CSS is awesome. Animations are awesome. So let's combine them! It's really easy to define your own custom animations with Tailwind.
Quick CSS animation refresher
A CSS animation is defined by creating a set of keyframes. These keyframes defi...]]></description><link>https://joeattardi.dev/using-animations-with-tailwind-css</link><guid isPermaLink="true">https://joeattardi.dev/using-animations-with-tailwind-css</guid><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[CSS Animation]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Thu, 26 Nov 2020 04:14:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/ddVk1aQrTWA/upload/a3623ebc612392ac02ec92670ed001e1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Tailwind CSS is awesome. Animations are awesome. So let's combine them! It's really easy to define your own custom animations with Tailwind.</p>
<h1 id="heading-quick-css-animation-refresher">Quick CSS animation refresher</h1>
<p>A CSS animation is defined by creating a set of <em>keyframes</em>. These keyframes define what CSS properties are applied at different points during the animation. When the animation is performed, the browser gradually transitions these properties between keyframes, creating an animation. Here's a simple example that makes an element spin:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> spin {
  0% { <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">rotate</span>(<span class="hljs-number">0deg</span>); }
  100% { <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">rotate</span>(<span class="hljs-number">360deg</span>); }
}
</code></pre>
<p>These keyframes define the animation, and they are applied by using the <code>animation</code> CSS property on an element. This is a shorthand property that allows you to set multiple animation-related properties, such as <code>animation-name</code> and <code>animation-duration</code>, in a single line.</p>
<p>Let's apply the <code>spin</code> animation to an element:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.box</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">200px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">200px</span>;
  <span class="hljs-attribute">background</span>: red;
  <span class="hljs-attribute">animation</span>: spin <span class="hljs-number">1s</span> infinite;
}
</code></pre>
<p>Here is the result:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/thinksInCode/pen/jOMOOVB">https://codepen.io/thinksInCode/pen/jOMOOVB</a></div>
<h1 id="heading-animating-with-tailwind">Animating with Tailwind</h1>
<p>Now that we remember how animation works with CSS, let's do it the Tailwind way. Tailwind ships with a few built-in animations, such as:</p>
<ul>
<li><code>spin</code></li>
<li><code>ping</code></li>
<li><code>pulse</code></li>
<li><code>bounce</code></li>
</ul>
<p>These animations can then be applied to an element by adding the class <code>animate-&lt;animation name&gt;</code>, e.g. <code>animate-spin</code>.</p>
<p>Let's say we want to do a fancier animation than the ones that are built in. Let's add a <code>roll</code> animation that moves and rotates the element. We can extend Tailwind to add new animation classes to do whatever we want.</p>
<p>To do this, you will need to edit your Tailwind configuration file. This is where the custom keyframes and animations are defined. These are set by specifying or extending the <code>keyframes</code> and <code>animations</code> properties in the theme.</p>
<p>First, let's define the keyframes:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {
      <span class="hljs-attr">keyframes</span>: {
        <span class="hljs-attr">roll</span>: {
          <span class="hljs-string">'0%, 100%'</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">'translateX(0) rotate(0deg)'</span> },
          <span class="hljs-string">'50%'</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">'translateX(20rem) rotate(385deg)'</span> }
        }
      }
    }
  }
};
</code></pre>
<p>As you can see, Tailwind lets you combine keyframes if they have the same CSS properties. The keyframes we've defined here have the element in its original position with no rotation at the beginning and the end of the animation. At the halfway point of the animation, the element is moved <code>20rem</code> to the right and rotated 385 degrees.</p>
<p>Next, we have to define an animation that uses these keyframes, under the <code>animations</code> property:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {
      <span class="hljs-attr">keyframes</span>: {
        <span class="hljs-attr">roll</span>: {
          <span class="hljs-string">'0%, 100%'</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">'translateX(0) rotate(0deg)'</span> },
          <span class="hljs-string">'50%'</span>: { <span class="hljs-attr">transform</span>: <span class="hljs-string">'translateX(20rem) rotate(385deg)'</span> }
        }
      },
      <span class="hljs-attr">animations</span>: {
        <span class="hljs-attr">roll</span>: <span class="hljs-string">'roll 3s ease-in-out infinite'</span>
      }
    }
  }
};
</code></pre>
<p>These changes will cause Tailwind to define a new class called <code>animate-roll</code>. All we have to do now is apply that class to an element, along with a little extra Tailwind styling, and we're done!</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-20"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"animate-roll bg-blue-600 border-2 border-blue-700 text-white px-8 py-2 rounded-md text-center w-40 font-bold text-xl"</span>&gt;</span>
    Hello Tailwind!
  <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>
</code></pre>
<p>The final result can be seen in <a target="_blank" href="https://play.tailwindcss.com/xSgo2Ah8fI?layout=horizontal">this Tailwind Play playground</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606363969903/9zSpe7PIx.gif" alt="Screen Recording 2020-11-25 at 11.10.05 PM.gif" /></p>
]]></content:encoded></item><item><title><![CDATA[JavaScript Maps vs Plain JavaScript Objects]]></title><description><![CDATA[ES2015, also known as ES6, added lots of new things to the JavaScript language. One very useful addition was the Map. Map allows you to map keys to values. 
Couldn't we already do that?
You might be thinking - we already could map keys to values in J...]]></description><link>https://joeattardi.dev/javascript-maps-vs-plain-javascript-objects</link><guid isPermaLink="true">https://joeattardi.dev/javascript-maps-vs-plain-javascript-objects</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[ES6]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Fri, 25 Sep 2020 15:36:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1601048142226/286uvuVMQ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>ES2015, also known as ES6, added lots of new things to the JavaScript language. One very useful addition was the <code>Map</code>. <code>Map</code> allows you to map keys to values. </p>
<h1 id="couldnt-we-already-do-that">Couldn't we already do that?</h1>
<p>You might be thinking - we already could map keys to values in JavaScript!</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> map = {};

map[key1] = value1;
map[key2] = value2;
</code></pre>
<p>You would be correct. Prior to ES2015, you could absolutely use JavaScript objects to map keys to values. However, there was an important limitation. When mapping with a JavaScript object, only strings may be used as keys. Consider the following:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> map = {};

<span class="hljs-keyword">const</span> key1 = { <span class="hljs-attr">foo</span>: <span class="hljs-string">'bar'</span> };
<span class="hljs-keyword">const</span> key2 = { <span class="hljs-attr">baz</span>: <span class="hljs-string">'qux'</span> };

map[key1] = <span class="hljs-number">100</span>;
map[key2] = <span class="hljs-number">200</span>;
</code></pre>
<p>Here we are taking two JavaScript objects and mapping them to some numbers. This is perfectly valid JavaScript; you won't get any errors when running this code. Let's see what happens when we try to retrieve these values:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(map[key2]); <span class="hljs-comment">// prints 200</span>
</code></pre>
<p>So far, so good. Now let's look up the first key:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(map[key1]); <span class="hljs-comment">// also prints 200</span>
</code></pre>
<p>Why does this print <code>200</code>, when in the above code we mapped <code>key1</code> to the value <code>100</code>? Let's investigate by looking at all the keys in the object <code>map</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">Object</span>.keys(map));
</code></pre>
<p>This will print out an array with a single key:</p>
<pre><code class="lang-javascript">[<span class="hljs-string">"[object Object]"</span>]
</code></pre>
<p>What's going on here? </p>
<p>It turns out, if you use a non-string key in a JavaScript object, the key is converted to a string by calling <code>toString</code> on it. For a plain JavaScript object, this results in the key <code>'[object Object]'</code>.</p>
<p>So when we set the first key in our <code>map</code> object, it was converted to that string, and everything would have worked as expected up to that point. However, when we added the second key, that was also converted to the same string value, so it overwrote the previous mapping. This is why the result will always be <code>200</code>.</p>
<h1 id="map-to-the-rescue"><code>Map</code> to the rescue</h1>
<p>The ES2015 <code>Map</code> can solve this problem for us. Like a plain object, it can map keys to values. Unlike plain objects, a <code>Map</code> can have non-string keys.</p>
<h2 id="creating-a-map">Creating a <code>Map</code></h2>
<p>Let's use the same example as above, only using a <code>Map</code> instead of a plain JavaScript object.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> map = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();

<span class="hljs-keyword">const</span> key1 = { <span class="hljs-attr">foo</span>: <span class="hljs-string">'bar'</span> };
<span class="hljs-keyword">const</span> key2 = { <span class="hljs-attr">baz</span>: <span class="hljs-string">'qux'</span> };

map.set(key1, <span class="hljs-number">100</span>);
map.set(key2, <span class="hljs-number">200</span>);

<span class="hljs-built_in">console</span>.log(map.get(key1)); <span class="hljs-comment">// prints 100</span>
<span class="hljs-built_in">console</span>.log(map.get(key2)); <span class="hljs-comment">// prints 200</span>
</code></pre>
<p>Now the mapping works as expected, because a <code>Map</code> can use objects as keys.</p>
<p>For more information about <code>Map</code>, see the excellent <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map">MDN documentation</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Introduction to Flexbox]]></title><description><![CDATA[All the cool kids may be using CSS Grid now, but there are still plenty of scenarios where Flexbox does exactly what you need. This article will give an introductory look at what you can do with Flexbox.
What is Flexbox?
Flexbox is the more commonly ...]]></description><link>https://joeattardi.dev/introduction-to-flexbox</link><guid isPermaLink="true">https://joeattardi.dev/introduction-to-flexbox</guid><category><![CDATA[CSS]]></category><category><![CDATA[flexbox]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Thu, 24 Sep 2020 18:18:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1600971492092/X6E5Jc0BS.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>All the cool kids may be using CSS Grid now, but there are still plenty of scenarios where Flexbox does exactly what you need. This article will give an introductory look at what you can do with Flexbox.</p>
<h1 id="what-is-flexbox">What is Flexbox?</h1>
<p>Flexbox is the more commonly used name for the <a target="_blank" href="https://www.w3.org/TR/css-flexbox-1/">CSS Flexible Box Layout Module</a>. It has very wide browser support. According to <a target="_blank" href="https://caniuse.com/flexbox">CanIUse.com</a>, it is fully supported in all modern browsers. It even has pretty decent support in IE11, though it can be buggy.</p>
<p>Flexbox is a one-dimensional layout. The <em>flex items</em> inside a <em>flex container</em> are laid out either in a horizontal row or a vertical column. There are several CSS properties that are used to fine-tune flexbox behavior when it comes to placement, sizing, and alignment.</p>
<h1 id="concepts">Concepts</h1>
<p>A quick note on concepts: I will describe the flow of flex layouts from left to right and top to bottom. This is usually how it works, but some locales flow text from right to left and so the default direction will be different. Make sure to keep this in mind when learning these concepts.</p>
<h2 id="main-axis">Main axis</h2>
<p>The <em>main axis</em> is the direction of the flex container. In a row flexbox container, the main axis is the horizontal axis, along the direction that the flex items are placed.</p>
<h2 id="cross-axis">Cross axis</h2>
<p>The <em>cross axis</em> is the direction perpendicular to the direction of the flex container. In a row flexbox container, the cross axis is the vertical axis.</p>
<h1 id="creating-a-flexbox-layout">Creating a flexbox layout</h1>
<p>It's very easy to create a flexbox layout. Just set an element's <code>display</code> property to <code>flex</code>. This will make the element a flex container. Any direct children will become flex items and will be laid out along the main axis.</p>
<p>To specify whether the flex container should be a row or column, set the <code>flex-direction</code> property to <code>row</code> or <code>column</code>, respectively.</p>
<p>The flex items will be flush against each other - by default, there is no spacing between them. Space can be added in two ways. The first, more widely supported way, is to just add <code>margin</code> to the flex items. There is another way to set uniform spacing of all flex items, by using the <code>gap</code> property. However, the <code>gap</code> property is only currently supported for flexbox in <a target="_blank" href="https://caniuse.com/flexbox-gap">a few browsers</a>.</p>
<p>Let's create a quick flex container. Here's the HTML:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</span>&gt;</span>1<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</span>&gt;</span>2<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</span>&gt;</span>3<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</span>&gt;</span>4<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>
</code></pre>
<p>And the accompanying CSS:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">background</span>: lightgray;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">20rem</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid black;
}

<span class="hljs-selector-class">.item</span> {
  <span class="hljs-attribute">background</span>: skyblue;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid red;
  <span class="hljs-attribute">text-align</span>: center;
}
</code></pre>
<p>Here's the result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600969609844/Ff46dBgQC.png" alt="Flexbox row container" /></p>
<p>You'll notice that the flex items are bunched together at the beginning of the main axis within the flex container.</p>
<h1 id="flex-grow"><code>flex-grow</code></h1>
<p>There are a few things we can do to change this behavior. First, we can specify a value for the <code>flex-grow</code> property on a flex item. When <code>flex-grow</code> is set, the item will grow to fill available space. The value is relative to the <code>flex-grow</code> value of other flex items.</p>
<p>If <code>flex-grow</code> is set to 1 across all items, they will grow equally:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600969810708/JMLtGOZJ1.png" alt="Screen Shot 2020-09-24 at 1.49.58 PM.png" /></p>
<p>If we set <code>flex-grow</code> to 1 across all items but set it to <code>2</code> for one of the items, that item will grow twice as much as the other items:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.item</span> {
  <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">1</span>;
}

<span class="hljs-selector-class">.item2</span> {
  <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">2</span>;
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600969892870/HJGd8VJP4.png" alt="Screen Shot 2020-09-24 at 1.51.21 PM.png" /></p>
<p>As you can see in the screenshot above, item 2 grows more than the other items. Twice as much, to be precise.</p>
<h1 id="the-justify-content-property">The <code>justify-content</code> property</h1>
<p>The <code>justify-content</code> property is set on the flex container. It specifies how the flex items are laid out along the main axis. The default value for this property is <code>flex-start</code>; it results in the behavior we've already seen. The flex items are bunched together at the beginning of the main axis.</p>
<p>There are several other useful values we can set for <code>justify-content</code>:</p>
<h2 id="center"><code>center</code></h2>
<p>The flex items are bunched together at the center of the main axis.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600970066795/x7JLRhXiB.png" alt="Screen Shot 2020-09-24 at 1.54.16 PM.png" /></p>
<h2 id="flex-end"><code>flex-end</code></h2>
<p>The flex items are bunched together at the end of the main axis.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600970101925/KS5uj1itO.png" alt="Screen Shot 2020-09-24 at 1.54.52 PM.png" /></p>
<h2 id="space-between"><code>space-between</code></h2>
<p>The first flex item is flush with the beginning of the main axis, the last item is flush with the end of the main axis, and the remaining items are spaced evenly between them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600970176340/wh089PXzF.png" alt="Screen Shot 2020-09-24 at 1.55.58 PM.png" /></p>
<h2 id="space-around"><code>space-around</code></h2>
<p>An equal amount of space is used between each flex item. On the inner flex items, this space "doubles up".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600970258476/jLVvPxfcG.png" alt="Screen Shot 2020-09-24 at 1.57.29 PM.png" /></p>
<h2 id="space-evenly"><code>space-evenly</code></h2>
<p>Equal spacing is used between all flex items.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600970330502/cdv-Djl2h6.png" alt="Screen Shot 2020-09-24 at 1.58.23 PM.png" /></p>
<h1 id="the-align-items-property">The <code>align-items</code> property</h1>
<p><code>align-items</code> is similar to <code>justify-content</code>, except it specifies how items are aligned along the <em>cross axis</em> of the flex container. </p>
<h2 id="flex-start"><code>flex-start</code></h2>
<p>The flex items are aligned to the start of the cross axis.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600970785421/lcEG9Y66G.png" alt="Screen Shot 2020-09-24 at 2.06.14 PM.png" /></p>
<h2 id="flex-end"><code>flex-end</code></h2>
<p>The flex items are aligned to the end of the cross axis.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600970905846/m3VHT2PFS.png" alt="Screen Shot 2020-09-24 at 2.08.18 PM.png" /></p>
<h2 id="center"><code>center</code></h2>
<p>The flex items are centered along the cross axis.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600970933042/v_MAbYWv2.png" alt="Screen Shot 2020-09-24 at 2.08.45 PM.png" /></p>
<h1 id="the-holy-grail-absolute-centering-with-flexbox">The holy grail: Absolute centering with flexbox</h1>
<p>The old joke of "How do you center a div?" is finally solved with flexbox. Simply set its container to be a flex container, and set both the <code>align-items</code> and <code>justify-content</code> properties to <code>center</code>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</span>&gt;</span>Item<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>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">background</span>: lightgray;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: row;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">20rem</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid black;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">20rem</span>;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-class">.item</span> {
  <span class="hljs-attribute">background</span>: skyblue;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">8rem</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid red;
  <span class="hljs-attribute">text-align</span>: center;
}
</code></pre>
<p>The <code>item</code> div is centered horizontally and vertically inside its container:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1600971139000/Ico4WwtN8.png" alt="Screen Shot 2020-09-24 at 2.12.10 PM.png" /></p>
<h1 id="further-learning">Further learning</h1>
<p>The best resource you'll ever find for flexbox is <a target="_blank" href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/">A Complete Guide to Flexbox</a> on CSS-Tricks. You'll find the properties we covered in this article along with many others to better tweak your flexbox layouts!</p>
<p>I hope you found this introduction to flexbox helpful.</p>
]]></content:encoded></item><item><title><![CDATA[Introduction to Custom Elements]]></title><description><![CDATA[Custom elements have pretty good browser support. Of course, they aren't supported in Internet Explorer, but that shouldn't surprise anyone.
If you don't need to support Internet Explorer 11, you can absolutely use Custom Elements today, as they are ...]]></description><link>https://joeattardi.dev/introduction-to-custom-elements</link><guid isPermaLink="true">https://joeattardi.dev/introduction-to-custom-elements</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[HTML]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Wed, 23 Sep 2020 15:13:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1600873999505/RNF4VEvI4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Custom elements have <a target="_blank" href="https://caniuse.com/custom-elementsv1">pretty good browser support</a>. Of course, they aren't supported in Internet Explorer, but that shouldn't surprise anyone.</p>
<p>If you don't need to support Internet Explorer 11, you can absolutely use Custom Elements today, as they are supported by all modern browsers.</p>
<h1 id="what-is-a-custom-element">What is a custom element?</h1>
<p>HTML has lots of built in elements, but Custom Elements allows you to create your own HTML elements with custom behavior. For example, I'm working on <a target="_blank" href="https://github.com/joeattardi/atomical">Atomical</a>, a custom element that displays a calendar.</p>
<p>In this article, we'll create a simple Click Counter element. It will render a button which displays the number of times it has been clicked.</p>
<h1 id="anatomy-of-a-custom-element">Anatomy of a custom element</h1>
<p>At its core, a custom element is simply a JavaScript class that extends from the <code>HTMLElement</code> class. It contains some lifecycle callback methods, which we'll get into in a moment. </p>
<p>Finally, that class is registered with the browser's <code>CustomElementRegistry</code> (which you can find under the <code>customElements</code> property of the <code>window</code> object). The class is registered with a given element name. One rule: the element name <em>must</em> contain a hyphen, to prevent it from clashing from current (and future!) HTML elements.</p>
<p>Another rule is when using custom elements, they must have a start and end tag, even when there is no child content - they cannot be self-closing.</p>
<h1 id="lifecycle-callbacks">Lifecycle callbacks</h1>
<p>There are a few lifecycle callbacks in a custom element. These are methods that are called by the browser at different points in the custom element's lifecycle. Here are the most commonly used lifecycle callbacks:</p>
<ul>
<li><code>connectedCallback</code> - Called when the element is added to the DOM. Usually used to render the initial HTML, add event listeners, etc.</li>
<li><code>disconnectedCallback</code> - Called when the element is removed from the DOM. Used to perform cleanup.</li>
<li><code>attributeChangedCallback</code> - Called whenever an attribute of the custom element has changed.</li>
</ul>
<h1 id="the-clickcounter-custom-element">The <code>ClickCounter</code> custom element</h1>
<p>Let's create our click counter. </p>
<h2 id="the-component-class">The component class</h2>
<p>The first step is to create our component class. In the <code>connectedCallback</code>, we'll create the button and add a <code>click</code> event listener to increment the counter. This is a simplified implementation; we aren't doing any cleanup in a <code>disconnectedCallback</code>, which we'd want to do in a real-world custom element. Let's keep it simple for now.</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ClickCounter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">HTMLElement</span> </span>{
  <span class="hljs-keyword">constructor</span>() {
    <span class="hljs-built_in">super</span>();
    <span class="hljs-built_in">this</span>.clickCount = <span class="hljs-number">0</span>;
  }

  connectedCallback() {
    <span class="hljs-keyword">const</span> buttonEl = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'button'</span>);
    buttonEl.innerHTML = <span class="hljs-built_in">this</span>.clickCount;

    buttonEl.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">this</span>.clickCount++;
      buttonEl.innerHTML = <span class="hljs-built_in">this</span>.clickCount;
    }
  }
}
</code></pre>
<h2 id="register-the-custom-element">Register the custom element</h2>
<p>Now that we've created the custom element class, let's register it with the <code>CustomElementRegistry</code>:</p>
<pre><code class="lang-javascript">customElements.define(<span class="hljs-string">'click-counter'</span>, ClickCounter);
</code></pre>
<h2 id="use-the-element">Use the element</h2>
<p>The last step is to use the <code>click-counter</code> element in our HTML:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Click Counter<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">click-counter</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">click-counter</span>&gt;</span>
</code></pre>
<p>This will render a button with a label of 0. Every time you click the button, the counter on the button's label will increment.</p>
<h1 id="live-code">Live code</h1>
<p>Here's a CodePen containing this example code that you can play with:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/thinksInCode/pen/xxVmexr">https://codepen.io/thinksInCode/pen/xxVmexr</a></div>
]]></content:encoded></item><item><title><![CDATA[How Emojis Work]]></title><description><![CDATA[In the process of writing Emoji Button, my plain JavaScript emoji picker (which turns one year old tomorrow, August 29th!), I have learned a lot about emojis! Hopefully someone out there will find this information useful, or at least interesting.
Emo...]]></description><link>https://joeattardi.dev/how-emojis-work</link><guid isPermaLink="true">https://joeattardi.dev/how-emojis-work</guid><category><![CDATA[emoji]]></category><dc:creator><![CDATA[Joe Attardi]]></dc:creator><pubDate>Sat, 29 Aug 2020 01:20:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1598664029003/Q7HYDgxae.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the process of writing <a target="_blank" href="https://emoji-button.js.org">Emoji Button</a>, my plain JavaScript emoji picker (which turns one year old tomorrow, August 29th!), I have learned a lot about emojis! Hopefully someone out there will find this information useful, or at least interesting.</p>
<p>Emojis are everywhere nowadays - SMS messages, Slack messages, even Git commit messages! But what makes these little smileys (and other icons) work?</p>
<h2 id="a-little-history">📜 A little history</h2>
<p>Emojis were predated by so-called "emoticons". These were sequences of characters that resembled faces with different expression, such as <code>:-)</code> for a smiley face. The emoticon first originated in electronic communications by Scott Fahlman on September 19, 1982, but their usage in printed text pre-dates even that. As early as the late 1800s (and possibly even earlier), sequences of print characters were proposed to represent different emotions.</p>
<p>There are several claims as to who invented the first graphical emoji characters, but they originally grew in popularity in Japan. Cell phone manufacturers began work to introduce their own emoji sets in the early 2000s.</p>
<p>Unicode is an industry standard for encoding of text. During the 2000s, Unicode gradually added emoji characters. Later that decade, it was suggested that Unicode consider creating a standard set of emojis that could be used across different platforms. Then, in 2009, the Unicode Technical Committee produced a proposed Unicode Emoji standard. Unicode 6.0 was the first version with a uniform set emojis.</p>
<h2 id="what-makes-an-emoji">⚙️ What makes an emoji?</h2>
<p>Under the hood, emojis are just sequences of Unicode code points. For example, the "face with tears of joy" emoji (😂) is the code point <code>U+1F602</code>. The most basic emojis are single Unicode code points.</p>
<h2 id="why-do-emojis-look-different-on-different-operating-systems">🎨 Why do emojis look different on different operating systems?</h2>
<p>The Emoji standard defines what code point sequences stand for what emojis, but doesn't dictate how they should look. Each operating system vendor creates their own images for these emoji characters and puts them all into the system font as glyphs.</p>
<h2 id="skin-tone-variations">👍🏼 Skin tone variations</h2>
<p>Unicode 8.0 added support for skin tone variations on human emojis. This is supported via a set of five modifiers based on the <a target="_blank" href="https://en.wikipedia.org/wiki/Fitzpatrick_scale">Fizpatrick scale</a> for measuring human skin color. These modifiers are themselves also Unicode code points, starting at <code>U+1F3FB</code> and ending at <code>U+1F3FF</code>.</p>
<p>To create a skin tone variant of an emoji, a sequence is used consisting of the main emoji code point followed by the skin tone modifier. So for example, a dark skinned thumbs-up emoji (👍🏿) would be represented by the sequence <code>U+1F44D U+1F3FF</code>.</p>
<h2 id="complex-emoji-sequences">👨‍🚀 Complex emoji sequences</h2>
<p>Some emojis don't have a single code point, but rather are expressed as sequences of other emoji code points - compound emojis, if you will. Here's an example: the male astronaut emoji (👨‍🚀). This is actually a combination of the man emoji (👨, <code>U+1F468</code>) and the rocket emoji (🚀, <code>U+1F680</code>).</p>
<p>But how does the system distinguish between an astronaut and a man followed by a rocket?</p>
<p>Enter the Zero Width Joiner (ZWJ).</p>
<p>The ZWJ, sometimes pronounced "zwidge", is not an emoji itself but is used in emoji sequences. Its code point is <code>U+200D</code>. It is an invisible character with, as its name implies, zero width.</p>
<p>The ZWJ is used as glue to attach different emoji code points together to create compound emoji sequences. Going back to our example of the male astronaut emoji, the sequence for this emoji would be <code>U+1F468 U+200D U+1F680</code>.</p>
<p>This can even be combined with a skin tone modifier to create a medium-skinned male astronaut (👨🏽‍🚀): <code>U+1F468 U+1F3FD U+200D U+1F680</code>. Note that the skin tone modifier, <code>U+1F3FD</code>, does not use a ZWJ. </p>
<h2 id="variation-selector-16">👁‍🗨 Variation Selector 16</h2>
<p>There is another special emoji code point, called Variation Selector 16, with a code point of <code>U+FE0F</code>. Some emojis also have a plain text presentation, which means they usually appear as a solid shape. For example, the heart emoji (❤️) has a plain text presentation (❤).</p>
<p>By default, these emojis will appear with the plain text presentation. The heart emoji code point is <code>U+2764</code>. This code point alone will result in the solid heart (❤).</p>
<p>To display these characters as their colorful emoji presentation, they are followed by Variation Selector 16. So to get the red heart, you would use the sequence <code>U+2764 U+FE0F</code>.</p>
<p>Some emoji sequences can have one (or more!) ZWJs and Variation Selector 16 characters. Take the example of the "eye in speech bubble" emoji (👁‍🗨). This is a complex sequence, <code>U+1F441 U+FE0F‍ U+200D U+1F5E8 U+FE0F</code>:</p>
<ul>
<li><code>U+1F441</code> eye</li>
<li><code>U+FE0F</code> Variation Selector 16</li>
<li><code>‍U+200D</code> Zero Width Joiner</li>
<li><code>U+1F5E8</code> left speech bubble</li>
<li><code>U+FE0F</code> Variation Selector 16</li>
</ul>
<h2 id="wrapping-up">🖖 Wrapping up</h2>
<p>There are some further emoji topics - additional modifiers, fully qualified vs. unqualified sequences, and more, but in the interests of time I won't cover those here. Maybe in a future post!</p>
<p>I hope you found this informative and that you learned something new about emojis! Think about this complexity the next time you send an emoji in a text message.</p>
]]></content:encoded></item></channel></rss>