<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:base="https://seanmcp.com/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>seanmcp.com</title>
    <link>https://seanmcp.com/</link>
    <atom:link href="https://seanmcp.com/rss.xml" rel="self" type="application/rss+xml" />
    <description>Technical guides, resources, and opinions from Sean McPherson</description>
    <language>en</language>
    <item>
      <title>We don&#39;t understand AI</title>
      <link>https://seanmcp.com/articles/we-dont-understand-ai/</link>
      <description>&lt;p&gt;While reading Ursula K. Le Guin&#39;s &lt;em&gt;The Farthest Shore&lt;/em&gt;, I was struck by this
quote from the main character:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To claim power over what you do not understand is not wise, nor is the end of
it likely to be good.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After thinking about AI all week at work, my brain connected that sentence to
the concept of &lt;strong&gt;interpretability&lt;/strong&gt;, our understanding of a model&#39;s inner
workings. An interpretable model is one that humans can understand its
decision-making processes. Is that the case for today&#39;s models?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;People outside the field are often surprised and alarmed to learn that we do
not understand how our own AI creations work. They are right to be
concerned...&lt;br&gt;–
&lt;a href=&quot;https://darioamodei.com/post/the-urgency-of-interpretability&quot;&gt;Dario Amodei, Anthropic&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We certainly have not solved interpretability&lt;br&gt;–
&lt;a href=&quot;https://www.theatlantic.com/technology/2025/09/if-anyone-builds-it-excerpt/684213/?gift=pRQoIbr977n_j7EMDgRW-4eiPRlePtRI-LA_w6dzMQI&amp;amp;utm_source=copy-link&amp;amp;utm_medium=social&amp;amp;utm_campaign=share&quot;&gt;Sam Altman, OpenAI&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Fictional characters know better than to harness an incomprensible power and
expect good. Why do we treat AI differently?&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Aside&lt;/strong&gt;: Moments like this are why you should read more and widely. There is
no end to previous wisdom that can be shared and reapplied to today&#39;s problems.&lt;/p&gt;
</description>
      <pubDate>Mon, 06 Jul 2026 14:14:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/we-dont-understand-ai/</guid>
    </item>
    <item>
      <title>What is VS Code doing?</title>
      <link>https://seanmcp.com/articles/what-is-vs-code-doing/</link>
      <description>&lt;p&gt;I have been a VS Code user for many years now. It was a soft landing from Atom
(RIP), and there haven&#39;t been any significant features from other editors that
have tempted me away. I have never experienced the performance issues that
others have cited. It wasn&#39;t always as cool as the competitors, but it worked
and worked well. Until recently.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/orgs/community/discussions/194075&quot;&gt;This week VS Code started adding&lt;/a&gt;
&lt;code&gt;Co-authored-by: Copilot &amp;lt;copilot@github.com&amp;gt;&lt;/code&gt; to my commit messages
&lt;em&gt;automatically&lt;/em&gt; when commiting from the UI. In two instances that I documented
at work, the commits included zero generative AI. But Copilot got the
attribution anyway. In a world with increasing contributions from AI, it is
important to me that any messaging about AI use is clear and accurate. This is
not, and I&#39;m disappointed that any decision makers working on VS Code thought
that this was a reasonable default.&lt;/p&gt;
&lt;p&gt;Then VS Code broke Intellisense – far and away its most valuable feature.
Instead of providing the fast and intuitive help that users have come to expect,
they have conceded to AI-powered Inline Suggestions. Previously the two systems
were battling for supremacy, but the result was usually reasonable: Intellisense
when it detected something and Inline Suggestions when it couldn&#39;t. It was a
&lt;em&gt;détente&lt;/em&gt; that I could live with. But now Inline Suggestions seem to have won
the war at the expense of users. Most painful to me are the loss of snippets and
automatic imports.&lt;/p&gt;
&lt;p&gt;At one point in time VS Code was the undeniable king of cross-platform code
editors. Then AI took over the engineering world and forks drew some folks away.
I&#39;ve enjoyed a lot of the AI-focused features that VS Code has implemented over
the years – he first few generations of GitHub Copilot were truly magic and
transformative for my work. But these most recent changes feel like crossing the
Rubicon. The progress &lt;em&gt;ad cacatum&lt;/em&gt; has begun and there is no going back.&lt;/p&gt;
&lt;p&gt;I&#39;m writing this in exile from Zed. I don&#39;t want to be here; I want my editor
back. But I&#39;m afraid that the writing is on the wall. /Lamentation&lt;/p&gt;
</description>
      <pubDate>Tue, 28 Apr 2026 19:47:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/what-is-vs-code-doing/</guid>
    </item>
    <item>
      <title>Defaults 2026</title>
      <link>https://seanmcp.com/articles/defaults-2026/</link>
      <description>&lt;ul&gt;
&lt;li&gt;Mail Client
&lt;ul&gt;
&lt;li&gt;Gmail app and Zoho app&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Mail Server
&lt;ul&gt;
&lt;li&gt;Gmail for personal email&lt;/li&gt;
&lt;li&gt;Zoho for professional email: I&#39;ve tried other providers for &lt;code&gt;@seanmcp.com&lt;/code&gt;
but keep coming back to Zoho. It&#39;s cheap, customizable, and provides all the
features that I want.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Notes
&lt;ul&gt;
&lt;li&gt;A private repo with shell scripts. Mobile notes are written in Google Keep
and manually backed up.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;To-Do
&lt;ul&gt;
&lt;li&gt;Todoist: I don&#39;t use most of the features, but I love the keyboard shortcut
on Mac to quickly add a TODO.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Phone Photo Shooting:
&lt;ul&gt;
&lt;li&gt;Default Android app&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Photo Management
&lt;ul&gt;
&lt;li&gt;Google Photos (though I&#39;m sad they removed the free tier for photo storage)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Calendar
&lt;ul&gt;
&lt;li&gt;Google Calendar: My wife and I have personal calendars and then a shared
family calendar.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cloud File Storage
&lt;ul&gt;
&lt;li&gt;Google Drive and Git&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RSS
&lt;ul&gt;
&lt;li&gt;Feedbin: I could probably get by on the free tier of another service, but
Feedbin is so nice and simple. I don&#39;t have to think about it when reading,
and I&#39;m not being upsold at every opportunity.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Contacts
&lt;ul&gt;
&lt;li&gt;Google Contacts: It recently added a new feature to add birthdays to the
calendar and give you a notification ahead of time. I almost built an app
that would do the same, and I&#39;m glad it&#39;s now a feature.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Browser
&lt;ul&gt;
&lt;li&gt;Microsoft Edge: Chromium-based with vertical tabs and the ability to remove
most features.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Chat
&lt;ul&gt;
&lt;li&gt;Text or WhatsApp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Bookmarks
&lt;ul&gt;
&lt;li&gt;A private repo with shell scripts. I migrated from Raindrop last Fall, and
it has been smooth enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Read It Later:
&lt;ul&gt;
&lt;li&gt;I leave things unread in Feedbin&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Word Processing
&lt;ul&gt;
&lt;li&gt;Google Docs and VS Code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Spreadsheets
&lt;ul&gt;
&lt;li&gt;Google Sheets&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Presentations
&lt;ul&gt;
&lt;li&gt;Google Slides: I&#39;ve tried code-based solutions, but it generally leads to
more tinkering and less preparation. I use all the default layouts and then
tweak the design once I&#39;m finished.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Shopping Lists
&lt;ul&gt;
&lt;li&gt;Google Keep: A note for groceries and another for shopping that are shared
with my wife&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Meal Planning
&lt;ul&gt;
&lt;li&gt;Google Keep (though this is mostly handled by my wife)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Budgeting and Personal Finance
&lt;ul&gt;
&lt;li&gt;A Google Sheet that is updated 1-2 times per year.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;News
&lt;ul&gt;
&lt;li&gt;National: AllSides, the Atlantic&lt;/li&gt;
&lt;li&gt;Local: Pittsburgh Post-Gazette, PublicSource, and Spotlight PA&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Music
&lt;ul&gt;
&lt;li&gt;YouTube Music: It&#39;s included with a YouTube Premium subscription and has
access to the all the music I want.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Podcasts
&lt;ul&gt;
&lt;li&gt;Pocket Casts: I like that it is focused on being a podcast player. I&#39;ve
tried other all-in-one options and keep going back to Pocket Casts. I&#39;ve
listened to 94 days and 22 hours since 2016.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Password Management
&lt;ul&gt;
&lt;li&gt;Bitwarden&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Code
&lt;ul&gt;
&lt;li&gt;VS Code: I&#39;ve tried Zed and Cursor as potential replacements, but neither of
them provide the right features with the right form.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Terminal
&lt;ul&gt;
&lt;li&gt;Terminal (Ubuntu): Not bad enough to look for alternatives&lt;/li&gt;
&lt;li&gt;iTerm2 (Mac): I like that it isn&#39;t trying to be anything other than a
terminal. I used Warp for a while but it became clear that their product
roadmap was not in the terminal space.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Search
&lt;ul&gt;
&lt;li&gt;DuckDuckGo: I&#39;m skeptical of AI summaries, and DDG is the only provider I&#39;ve
found that allows you to disable them. That said: the results aren&#39;t great.
If you have an alternative, please let me know.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Wed, 28 Jan 2026 13:48:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/defaults-2026/</guid>
    </item>
    <item>
      <title>AI use case: Asking questions of large files</title>
      <link>https://seanmcp.com/articles/ai-use-case-asking-questions-of-large-files/</link>
      <description>&lt;p&gt;Khan Academy
&lt;a href=&quot;https://blog.khanacademy.org/genqlient-a-truly-type-safe-go-graphql-client/&quot;&gt;uses GraphQL&lt;/a&gt;
to handle all request to query and mutate data. Each service in the system
contributes to the GraphQL schema, and everything is ultimately combined into a
single file. If a developer wants to know what our API can do, the answer is in
that file.&lt;/p&gt;
&lt;p&gt;The problem is that &lt;strong&gt;it&#39;s over 80,000 lines long&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Most of the time you can get by searching the file for keywords. If you&#39;re
interested in the user or classrooms or a specific feature, you can find
breadcrumbs that lead you to the answer. But sometimes you&#39;re dealing with
unfamiliar terms or features old enough to have been renamed over the past
decade. File search alone won&#39;t always get the job done.&lt;/p&gt;
&lt;p&gt;Yesterday I was in this situation and turned to Copilot in VS Code. I switched
it to &amp;quot;Ask&amp;quot; mode and entered my query: &amp;quot;How can I determine if a user is in a
given district?&amp;quot; The model interpreted by question, read the file in chunks, and
then returned an answer.&lt;/p&gt;
&lt;p&gt;Of the options provided, only one included the exact terms that I had in my
query. After inspecting the response, I found that the best option used an old
term that we don&#39;t use anymore and I&#39;ve never heard. I would not have found that
by searching the file by myself. Uncovering the answer was only possible with an
LLM.&lt;/p&gt;
&lt;p&gt;I&#39;m generally skeptical of using AI to write production code that matters. But
as a search tool, I&#39;m increasingly convinced that they are a powerful addition
to a developer&#39;s toolbox. When file search can&#39;t surface the answer, the ability
to ask questions of large files with an LLM is a valuable resource.&lt;/p&gt;
</description>
      <pubDate>Wed, 07 Jan 2026 12:50:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/ai-use-case-asking-questions-of-large-files/</guid>
    </item>
    <item>
      <title>Install curl with apt (and not snap)</title>
      <link>https://seanmcp.com/articles/install-curl-with-apt-and-not-snap/</link>
      <description>&lt;p&gt;After switching my desktop to Linux from Windows&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/install-curl-with-apt-and-not-snap/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, I ran into an issue installing Node. The official directions
recommend using &lt;code&gt;nvm&lt;/code&gt;, but the &lt;code&gt;nvm install 24&lt;/code&gt; command was failing with a lack
of permissions:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Downloading and installing node v24.6.0...
Downloading https://nodejs.org/dist/v24.6.0/node-v24.6.0-linux-x64.tar.xz...
Warning: Failed to open the file /home/seanmcp/.nvm/.cache/bin/node-v24.6.0-linux-x64/node-v24.6.0-linux-x64.tar.xz: Permission denied
curl: (23) client returned ERROR on write of 1360 bytes

download from https://nodejs.org/dist/v24.6.0/node-v24.6.0-linux-x64.tar.xz failed
grep: /home/seanmcp/.nvm/.cache/bin/node-v24.6.0-linux-x64/node-v24.6.0-linux-x64.tar.xz: No such file or directory
Provided file to checksum does not exist.
Binary download failed, trying source.
Downloading https://nodejs.org/dist/v24.6.0/node-v24.6.0.tar.xz...

Warning: Failed to open the file /home/seanmcp/.nvm/.cache/src/node-v24.6.0/node-v24.6.0.tar.xz: Permission denied
curl: (23) client returned ERROR on write of 1360 bytes

download from https://nodejs.org/dist/v24.6.0/node-v24.6.0.tar.xz failed
grep: /home/seanmcp/.nvm/.cache/src/node-v24.6.0/node-v24.6.0.tar.xz: No such file or directory
Provided file to checksum does not exist.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The permissions in the &lt;code&gt;.nvm/.cache/&lt;/code&gt; directory looked fine,
&lt;a href=&quot;https://xkcd.com/149/&quot;&gt;&lt;code&gt;sudo&lt;/code&gt; didn&#39;t work&lt;/a&gt;, and Claude Sonnet 4 wasn&#39;t helpful.
I went searching online and found
&lt;a href=&quot;https://askubuntu.com/a/1489138&quot;&gt;a question and answer from three years ago&lt;/a&gt;
that recommended:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Uninstalling &lt;code&gt;curl&lt;/code&gt; with snap: &lt;code&gt;sudo snap remove curl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Reinstalling &lt;code&gt;curl&lt;/code&gt; with apt: &lt;code&gt;sudo apt install curl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Running the nvm/Node install commands again&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Doing that fixed the issue for me.&lt;/p&gt;
&lt;p&gt;I would have never considered &lt;code&gt;curl&lt;/code&gt; as possible source of my issues. So I&#39;m
thankful that questions/answers like that exist on the internet.&lt;/p&gt;
&lt;p&gt;I think I need to learn about the differences between apt and snap, and why you
would choose one versus the other. If you have a good resources for that, please
let me know.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;My build was incompatible and
Windows 11, and I didn&#39;t want to upgrade to use an operating system that I am
ambivalent about. &lt;a href=&quot;https://seanmcp.com/articles/install-curl-with-apt-and-not-snap/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 25 Aug 2025 11:50:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/install-curl-with-apt-and-not-snap/</guid>
    </item>
    <item>
      <title>Four perspectives on AI</title>
      <link>https://seanmcp.com/articles/four-perspectives-on-ai/</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://frontendatscale.com/issues/46&quot;&gt;Maxi Ferreira writes in &lt;em&gt;Fear and Curiosity and AI&lt;/em&gt;&lt;/a&gt;
about the two stages of AI adoption among developers:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A Stage 1 reaction looks something like this: “Ha! Look at this dumb mistake
the AI made. It thought I was using Tailwind when I’m actually using Style
Components. More like Artificial Unintelligence, am I right? Good luck taking
my job, bots.”&lt;/p&gt;
&lt;p&gt;A Stage 2 reaction looks more like this: “Hmm, I wonder why the AI got
confused there. Maybe some of my classes in this component look like Tailwind
classes. How can I prevent this from happening in the future? Let me add a
Cursor Rule to tell it I’m actually using Styled Components in this project.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The naming suggestions a progression. Developers start at the defensive/fearful
Stage 1 but are able to progress to Stage 2 with a &amp;quot;curiosity mindset&amp;quot;.&lt;/p&gt;
&lt;p&gt;I agree with Ferreira about the two reactions. I feel like I&#39;ve heard them both
near verbatim while talking about AI with colleagues. And I agree that curiosity
and a growth mindset are invaluable in our field and life broadly. But the
framing of &amp;quot;Stage 1/Stage 2&amp;quot; and the motivation behind them is uncharitable (at
best) and unhelpful (at worst).&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/four-perspectives-on-ai/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;The difference between the two reactions depends not on time and mindset but on
an individual&#39;s belief of AI&#39;s transformative potential and positive impact.&lt;/p&gt;
&lt;img src=&quot;https://seanmcp.com/img/beliefs-about-ai.png&quot; alt=&quot;A two-axis graph labeled &#39;Beliefs about AI&#39; with the x-axis of &#39;Transformative&#39; and the y-axis of &#39;Positive&#39;. The field is divided into four quadrants: &#39;Skeptical&#39; in the bottom-left, &#39;Wary&#39; in the bottom-right, &#39;Pragmatist&#39; in the top-left, and &#39;Optimist&#39; in the top-right.&quot;&gt;
&lt;p&gt;The &lt;strong&gt;Skeptical&lt;/strong&gt; see AI&#39;s capabilities and limitations. They question the
imminent advent of AGI and whether future frontier models will have a
significant impact on the world in the long-term. They don&#39;t see the
technological developments of AI as a net positive. They&#39;ll use phrases like
&amp;quot;over-hyped&amp;quot; and &amp;quot;flash in the pan&amp;quot;. They are unlikely to experiment with AI
tools. When they see the output of any-given model, they tend to have Reaction 1
because criticism illustrates their beliefs.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Wary&lt;/strong&gt; also see AI&#39;s capabilities and limitations but believe that
developments in the field will result in dramatic changes to our work and lives.
They are concerned that the advancement of this technology will come at severe
cost to other aspects of our world. They&#39;ll have a &amp;quot;p(doom)&amp;quot; number, raise
concerns about safety, and cite environmental or societal detriments of AI. They
may have Reaction 1 but are more likely to avoid AI entirely and encourage
others to do the same.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Pragmatic&lt;/strong&gt; aren&#39;t swayed by arguments for or projections of AGI. They see
AI as a tool to help them with tasks today. They&#39;ll experiment with prompts and
models but will quickly move on when it isn&#39;t working. They&#39;ll mention
&amp;quot;usefulness&amp;quot;, &amp;quot;utility&amp;quot;, and &amp;quot;productivity&amp;quot;. They spend little time thinking
about AI beyond a specific problem and solution. They may have Reaction 2,
though there will be a reasonable time box for how long they explore.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Optimistic&lt;/strong&gt; see the potential in AI&#39;s capabilities and trust that the
limitations will eventually be overcome. They believe that future models will
radically transform our world for the better citing problems to be solved in
medicine and the environment. They&#39;ll encourage others to learn how to use AI so
that they &amp;quot;don&#39;t get left behind&amp;quot;. They tend to have Reaction 2 and will push
the boundaries of what is capable with the current state of AI.&lt;/p&gt;
&lt;p&gt;I&#39;ve grouped these four perspectives, but everything here is a spectrum.
Depending on the context or day, you might find yourself at any point on the
graph. And I&#39;ve attempted to describe each perspectively generously, because I
don&#39;t believe that any are inherently good or bad. I find myself switching
between perspectives throughout the day as I implement features, use tools, and
read articles. A good team is probably made of members from all perspectives.&lt;/p&gt;
&lt;p&gt;Which perspective resonates with you today? Do you also find yourself moving
around the graph?
&lt;a href=&quot;mailto:sean@seanmcp.com?subject=RE:%20Four%20perspectives%20on%20AI&quot;&gt;I would love to hear your thoughts&lt;/a&gt;,
as I&#39;m sure mine will continue to develop over time.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Despite my disagreement with Ferreira, I still
recommend &lt;a href=&quot;https://frontendatscale.com/&quot;&gt;his newsletter&lt;/a&gt;. It has helpful
insights and interesting links that I&#39;m happy to see in my inbox. &lt;a href=&quot;https://seanmcp.com/articles/four-perspectives-on-ai/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Wed, 20 Aug 2025 10:24:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/four-perspectives-on-ai/</guid>
    </item>
    <item>
      <title>Axe DevTools doesn&#39;t flag multiple h1 elements on a page</title>
      <link>https://seanmcp.com/articles/axe-devtools-doesnt-flag-multiple-h1-elements-on-a-page/</link>
      <description>&lt;p&gt;The
&lt;a href=&quot;https://www.deque.com/get-started-axe-devtools-browser-extension/&quot;&gt;axe DevTools extension&lt;/a&gt;
is valuable for testing the quality of your work. I use it multiple times per
day when working on frontend tasks. So I was surprised today when I learned that
axe does not consider multiple &lt;code&gt;h1&lt;/code&gt; elements on a page an issue.&lt;/p&gt;
&lt;p&gt;It turns out that this is intentional. There is no rule stating that pages
cannot have more than one &lt;code&gt;h1&lt;/code&gt;–even if it is widely considered best
practice&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/axe-devtools-doesnt-flag-multiple-h1-elements-on-a-page/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.
&lt;a href=&quot;https://www.a11yproject.com/posts/how-to-accessible-heading-structure/#one-h1&quot;&gt;The A11y Project has a nice write up on the topic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even though axe doesn&#39;t consider it an issue, I still want to avoid rendering
more than one &lt;code&gt;h1&lt;/code&gt; on a page.
&lt;a href=&quot;https://gist.github.com/SeanMcP/ed0ad9685b0a7aa78b457f4301fb37de&quot;&gt;I previously wrote a little script to print all of a webpage&#39;s headings to the console&lt;/a&gt;,
and I wanted to make that as easy to use as axe. Thankfully we can do that with
&lt;a href=&quot;https://developer.chrome.com/docs/devtools/javascript/snippets&quot;&gt;Chromium&#39;s snippets API&lt;/a&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/axe-devtools-doesnt-flag-multiple-h1-elements-on-a-page/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the browser devtools&lt;/li&gt;
&lt;li&gt;Select the &amp;quot;Sources&amp;quot; panel&lt;/li&gt;
&lt;li&gt;In the left-hand panel, select the &amp;quot;Snippets&amp;quot; tab (it might be hidden in the
caret menu)&lt;/li&gt;
&lt;li&gt;Select &amp;quot;New snippet&amp;quot;&lt;/li&gt;
&lt;li&gt;Name it something like &amp;quot;Print headings&amp;quot;&lt;/li&gt;
&lt;li&gt;Paste the code from my gist:&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;h1,h2,h3,h4,h5,h6,[role=heading][aria-level]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; level &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;aria-level&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tagName&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; prefix &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;level&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;prefix&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;level&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Save the snippet&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can run snippets from the Sources panel, but the faster way is to use the
keyboard shortcut:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the browser devtools, press &lt;kbd&gt;ctrl/cmd&lt;/kbd&gt;+&lt;kbd&gt;o&lt;/kbd&gt; to open the
command menu&lt;/li&gt;
&lt;li&gt;Type &amp;quot;!&amp;quot; to bring up the list of snippets&lt;/li&gt;
&lt;li&gt;Select your snippet from the list&lt;/li&gt;
&lt;li&gt;Press &lt;kbd&gt;enter/return&lt;/kbd&gt; to run it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The snippet will execute and print all of the headings on the page to the
console.&lt;/p&gt;
&lt;p&gt;You could do more in your version of the snippet like validating the existence
of a single &lt;code&gt;h1&lt;/code&gt; or the heading order. For me, having it print the headings is
good enough to spot check my work.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Axe&#39;s has a &amp;quot;Best Practices&amp;quot; option, but that doesn&#39;t flag it
either. &lt;a href=&quot;https://seanmcp.com/articles/axe-devtools-doesnt-flag-multiple-h1-elements-on-a-page/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I
couldn&#39;t find an equivalent for Firefox (and didn&#39;t check Safari). If I&#39;ve
missed it, let me know and I&#39;ll update this article to include information for
other browsers. &lt;a href=&quot;https://seanmcp.com/articles/axe-devtools-doesnt-flag-multiple-h1-elements-on-a-page/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Wed, 16 Jul 2025 18:40:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/axe-devtools-doesnt-flag-multiple-h1-elements-on-a-page/</guid>
    </item>
    <item>
      <title>Writing code was never the bottleneck in software engineering</title>
      <link>https://seanmcp.com/articles/writing-code-was-never-the-bottleneck-in-software-engineering/</link>
      <description>&lt;p&gt;&lt;em&gt;Writing Code Was Never the Bottleneck&lt;/em&gt; by Pedro Tavares makes an important
observation about using LLMs when writing software. The problem as stated by the
solution is that writing code is primarily the bottleneck in development. &amp;quot;If
only we could write code faster, then we&#39;d be able to ship more features.&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ordep.dev/posts/writing-code-was-never-the-bottleneck&quot;&gt;Tavares challenges that presupposition&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The actual bottlenecks were, and still are, code reviews, knowledge transfer
through mentoring and pairing, testing, debugging, and the human overhead of
coordination and communication. All of this wrapped inside the labyrinth of
tickets, planning meetings, and agile rituals.&lt;br&gt;&lt;br&gt;These processes, meant
to drive quality, often slow us down more than the act of writing code itself
because they require thought, shared understanding, and sound
judgment.&lt;br&gt;&lt;br&gt;...&lt;br&gt;&lt;br&gt; The marginal cost of adding new software is
approaching zero, especially with LLMs. But what is the price of
understanding, testing, and trusting that code? Higher than ever.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When engineering software for an organization, writing code is rarely the hard
part. It&#39;s everything that precedes and follows writing code that slows you
down: gathering requirements, exploring existing patterns, reviewing pull
requests, testing solutions, sharing knowledge. LLMs can supercharge the
generation of code, but they make the rest of the process slower.&lt;/p&gt;
&lt;p&gt;Judicious use can result in modest productivity improvements. But stray too far
and suddenly you&#39;re spending more time to assure quality or waving it away with
&amp;quot;vibes&amp;quot;.&lt;/p&gt;
&lt;p&gt;Tavares&#39; observation also explains why using LLMs in greenfield or prototype
environments feels so different. In those situations, writing code &lt;em&gt;is&lt;/em&gt; the
bottleneck and generating code with an LLM blows it wide open. The tech debt
created by using LLM code takes time to be noticed and may never come up (&lt;em&gt;e.g.&lt;/em&gt;
sacrificial prototypes).&lt;/p&gt;
&lt;p&gt;But in a software-development environment, the equation changes. Requirements,
understanding, reviews, and testing take priority. In that world, generating
huge swaths of code with LLMs only exacerbates the true bottlenecks of software
engineering. The craft becomes learning how to use them well without creating
more problems for your team down the road.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Hat tip to &lt;a href=&quot;https://cassidoo.co/newsletter/&quot;&gt;Rendezvous with Cassidoo&lt;/a&gt; for
sharing the article.&lt;/p&gt;
</description>
      <pubDate>Wed, 09 Jul 2025 11:05:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/writing-code-was-never-the-bottleneck-in-software-engineering/</guid>
    </item>
    <item>
      <title>Colocate functionally-related code</title>
      <link>https://seanmcp.com/articles/colocate-functionally-related-code/</link>
      <description>&lt;p&gt;I read &lt;a href=&quot;https://kentcdodds.com/blog/colocation&quot;&gt;&lt;em&gt;Colocation&lt;/em&gt; by Kent C. Dodds&lt;/a&gt;
back in 2019 before I had an opinion on the topic. Six years later, I&#39;ve come to
a similar conclusion. Generally speaking, we should keep related code as close
together as possible.&lt;/p&gt;
&lt;p&gt;Common related code in my work are components, styles, tests, and stories. My
preference is to keep all of these files together in the same directory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;components/
    ├── my-component.tsx
    ├── my-component.css
    ├── my-component.test.tsx
    └── my-component.stories.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A change to one will often require a change to one or more others. By keeping
the code together in your file system, you both remind yourself of that fact and
make it easier to find the other files that need to change.&lt;/p&gt;
&lt;p&gt;The major alternative pattern I see are dedicated directories for each
&amp;quot;concern&amp;quot;: &lt;code&gt;__tests__&lt;/code&gt;, &lt;code&gt;__stories__&lt;/code&gt;, &lt;em&gt;etc&lt;/em&gt;. By one definition of related, this
is a method of colocating related code. Everything in those directories is
related to the same domain and has some things in common.&lt;/p&gt;
&lt;p&gt;But rarely do I need to update &amp;quot;all test files.&amp;quot; And when I do the filename
pattern is sufficient to find them. In contrast, every day I need to update
functionally-related code. So I want my organization system to prioritize the
work that occurs most frequently.&lt;/p&gt;
&lt;p&gt;Colocate all of your functionally-related code.&lt;/p&gt;
</description>
      <pubDate>Mon, 30 Jun 2025 18:30:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/colocate-functionally-related-code/</guid>
    </item>
    <item>
      <title>My on-again-off-again relationship with AI assistants</title>
      <link>https://seanmcp.com/articles/my-on-again-off-again-relationship-with-ai-assistants/</link>
      <description>&lt;p&gt;For the past few years, I have been paying on and off for ChatGPT and Claude. I
will read an interesting story about how someone transformed their work with AI,
then sign up for a premium plan for one month. I spend a few days actively
engaging with the AI and then quickly fall off. I go weeks without chatting with
the assistant and then cancel before the month is up.&lt;/p&gt;
&lt;p&gt;There is a lot of smoke in the work-productivity AI space. I believe there is
(probably) fire there somewhere. But I haven&#39;t been able to find it.&lt;/p&gt;
&lt;p&gt;Beyond one-off questions that require more nuance than a search on StackOverflow
or quick chats about naming things&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/my-on-again-off-again-relationship-with-ai-assistants/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, I struggle to find
many use cases for an AI assistant. I don&#39;t know if that is a result of how I
think and work or a limitation of the product. But it&#39;s not working for me.&lt;/p&gt;
&lt;p&gt;GitHub Copilot is a little different. It continues to churn in the background
while I code, and I frequently utilize its autocompletions. Sometimes the
refactors are usable, but others they are way off. I have been experimenting
with the more &amp;quot;agentic&amp;quot; features, but I&#39;m finding that reviewing the generated
code takes a comparable amount of time to writing it myself. And writing code is
more fun than reviewing.&lt;/p&gt;
&lt;p&gt;I find AI assistants useful, just less so than other folks online. I&#39;m glad to
have them as an option&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/my-on-again-off-again-relationship-with-ai-assistants/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; but am still on the lookout
for a reason to pay $20/month for a premium plan. If that all resonants and you
have some suggestions, please reach out. I can be convinced!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;A famously hard problem &lt;a href=&quot;https://seanmcp.com/articles/my-on-again-off-again-relationship-with-ai-assistants/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I am especially thankful for the free access to GitHub
Copilot that I am granted every month. I don&#39;t know what I did to qualify for
this program and at this point am afraid to ask! &lt;a href=&quot;https://seanmcp.com/articles/my-on-again-off-again-relationship-with-ai-assistants/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 31 Mar 2025 10:18:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/my-on-again-off-again-relationship-with-ai-assistants/</guid>
    </item>
    <item>
      <title>Zed still isn&#39;t ready</title>
      <link>https://seanmcp.com/articles/zed-still-isnt-ready/</link>
      <description>&lt;p&gt;VS Code started acting up after a recent update, so I took the opportunity to
&lt;a href=&quot;https://seanmcp.com/articles/zed-is-a-rocket-powered-skateboard&quot;&gt;try Zed again&lt;/a&gt;. It has improved
since my last attempt and was a perfectly workable editor for small stuff.&lt;/p&gt;
&lt;p&gt;The cracks started to show when I used it with a large codebase. The search was
incredibly slow—much slower than VS Code. And since it doesn&#39;t preserve filter
settings between queries, every subsequent search was slow too.&lt;/p&gt;
&lt;p&gt;I liked some of the code actions like autofix imports, but I never felt
confident that Zed would select the right file. At work we have some duplicate
file names and exports, so it is important to be able to choose which &lt;code&gt;View&lt;/code&gt;
component to import.&lt;/p&gt;
&lt;p&gt;The biggest issue I encountered was around memory and possible leaks. Zed (for
some reason) supports looking up all references for primatives like &lt;code&gt;false&lt;/code&gt;,
which would crash my M2 Mac by scouring the whole codebase for every instance of
&lt;code&gt;false&lt;/code&gt;. Today it crashed when I searched for a term with too many matches.&lt;/p&gt;
&lt;p&gt;I couldn&#39;t get AI completions working correctly (despite installing and
registering with GitHub Copilot) nor the unit test runner.&lt;/p&gt;
&lt;p&gt;Zed is promising, and I think they nail a lot of the intangibles that make a
product desirable. But it still isn&#39;t ready for full-time development work.&lt;/p&gt;
</description>
      <pubDate>Thu, 16 Jan 2025 24:30:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/zed-still-isnt-ready/</guid>
    </item>
    <item>
      <title>Deleting my GPTs</title>
      <link>https://seanmcp.com/articles/deleting-my-gpts/</link>
      <description>&lt;p&gt;Today I deleted all of my public and private
&lt;a href=&quot;https://openai.com/index/introducing-gpts/&quot;&gt;GPTs&lt;/a&gt;. I thought I would feel sad:
they were the feature that convinced me to start paying for OpenAI last year.
But instead it feels like an anticlimactic end to an experiment.&lt;/p&gt;
&lt;p&gt;When custom GPTs were initially launched, I was interested in an official
playground for prompt engineering with the potential of a marketplace. I spun up
a few and even &lt;a href=&quot;https://seanmcp.com/tags/gpts&quot;&gt;wrote some articles about it&lt;/a&gt;. But the feature
fizzled and the market hasn&#39;t panned out.&lt;/p&gt;
&lt;p&gt;Beyond a questionably-accurate conversation count, OpenAI doesn&#39;t provide even
basic usage data. Critical measures like recent sessions, average conversation
length, and bounce rate are all missing. Maybe you could overlook that if your
GPTs made a few bucks a month, but there is no market and no clear road to one.&lt;/p&gt;
&lt;p&gt;That was enough to convince me, but paying for the privilege of keeping these
GPTs online wore me down too. I don&#39;t like being tied down with subscription
services, and GPTs were the only thing keeping me in the OpenAI ecosystem. So I
deleted them.&lt;/p&gt;
&lt;p&gt;Without the GPTs, I&#39;m free to switch to Claude (which all my cool
prompt-engineer friends say is better) or nothing at all. $20 a month goes
pretty far at a food bank or international charity.&lt;/p&gt;
&lt;p&gt;If you were a faithful user of my GPTs, then I apologize for the change. But
dozens of users are not enough to justify the expense or the lock-in. Send me an
email, and I will share everything you need to make your own.&lt;/p&gt;
</description>
      <pubDate>Tue, 12 Nov 2024 24:38:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/deleting-my-gpts/</guid>
    </item>
    <item>
      <title>Pittsburgh TechFest 2024</title>
      <link>https://seanmcp.com/articles/pittsburgh-techfest-2024/</link>
      <description>&lt;p&gt;Yesterday I went to
&lt;a href=&quot;https://www.pghtech.org/events/2024TechFest&quot;&gt;Pittsburgh TechFest 2024&lt;/a&gt; at the
Commonwealth Charter Academy building on the Waterfront. The venue was nice, the
food was good, and both keynotes were interesting—though I definitely did not
know enough about SNL to fully appreciate the closing.&lt;/p&gt;
&lt;p&gt;My favorite talk was by Dominika Blach of the Greater Pittsburgh Community Food
Bank about how they&#39;re using low-code solutions for an organization that needs
technology solutions but can&#39;t afford developers. I knew nothing about low code
but can imagine a lot of organizations with similar constraints who need
professionals who can navigate that world for them.&lt;/p&gt;
&lt;p&gt;I gave a talk title
&lt;em&gt;&lt;a href=&quot;https://seanmcp.com/talks/thinking-outside-the-bots&quot;&gt;Thinking Outside the Bots&lt;/a&gt;: A human-centric
approach to model interactions&lt;/em&gt; and discussed some of my thoughts about how we
build features using AI&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/pittsburgh-techfest-2024/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. I got to share some of the cool things that I&#39;ve
been working on at Khan Academy and felt validated by the responses. The talk
was well received, sparking interesting conversations afterwards and a couple
invitations to give the talk again to other groups.&lt;/p&gt;
&lt;p&gt;For the first time, I enjoyed the networking side of the event more than the
talks. I had the chance to reconnect with some former colleagues at Niche, met
some of the folks from Carnegie Learning, talked with friends, and saw a lot of
familiar faces from last year. I handed out some business cards (vintage 2017)
and made some good connections.&lt;/p&gt;
&lt;p&gt;It&#39;s hard to feel connected to the local tech scene when you work remotely for a
company based 2,200 miles away. So I think it&#39;s important for workers like me to
invest time in events like this. Looking forward to next year!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;tl;dr I think that chatbots are a bad UI for most use cases and that we
should focus our design efforts on user needs and defined outcomes &lt;a href=&quot;https://seanmcp.com/articles/pittsburgh-techfest-2024/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Sat, 28 Sep 2024 10:31:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/pittsburgh-techfest-2024/</guid>
    </item>
    <item>
      <title>Bypass &quot;Error: There are no prompts&quot; in promptfoo</title>
      <link>https://seanmcp.com/articles/bypass-error-there-are-no-prompts-in-promptfoo/</link>
      <description>&lt;p&gt;While evaluating different language models with
&lt;a href=&quot;https://promptfoo.com/&quot;&gt;promptfoo&lt;/a&gt;, I started running into the following error
message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/Users/seanmcp/project-dir/node_modules/.pnpm/promptfoo@0.67.0_@aws-sdk+client-bedrock-runtime@3.606.0_@azure+identity@4.3.0_@azure+openai-_c7fwzdecwpaax3yh5ny536i2qu/node_modules/promptfoo/dist/src/prompts/index.js:136
            throw new Error(`There are no prompts in ${JSON.stringify(prompt.raw)}`);
                  ^

Error: There are no prompts in &amp;quot;TEXT_OF_THE_PROMPT_THAT_I_TRIED_TO_EVALUATE&amp;quot;
    at readPrompts (/Users/seanmcp/project-dir/node_modules/.pnpm/promptfoo@0.67.0_@aws-sdk+client-bedrock-runtime@3.606.0_@azure+identity@4.3.0_@azure+openai-_c7fwzdecwpaax3yh5ny536i2qu/node_modules/promptfoo/dist/src/prompts/index.js:136:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async resolveConfigs (/Users/seanmcp/project-dir/node_modules/.pnpm/promptfoo@0.67.0_@aws-sdk+client-bedrock-runtime@3.606.0_@azure+identity@4.3.0_@azure+openai-_c7fwzdecwpaax3yh5ny536i2qu/node_modules/promptfoo/dist/src/main.js:129:27)
    at async runEvaluation (/Users/seanmcp/project-dir/node_modules/.pnpm/promptfoo@0.67.0_@aws-sdk+client-bedrock-runtime@3.606.0_@azure+identity@4.3.0_@azure+openai-_c7fwzdecwpaax3yh5ny536i2qu/node_modules/promptfoo/dist/src/main.js:545:48)
    at async Command.&amp;lt;anonymous&amp;gt; (/Users/seanmcp/project-dir/node_modules/.pnpm/promptfoo@0.67.0_@aws-sdk+client-bedrock-runtime@3.606.0_@azure+identity@4.3.0_@azure+openai-_c7fwzdecwpaax3yh5ny536i2qu/node_modules/promptfoo/dist/src/main.js:704:9)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It didn&#39;t occur for a long time, but then started occurring every time I added a
new prompt to the config. Clearing the cache did not help.&lt;/p&gt;
&lt;p&gt;The only solution I found was to add a space to the end of the prompt text:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;prompts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TEXT_OF_THE_PROMPT_THAT_I_TRIED_TO_EVALUATE &quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This enabled promptfoo to run as expected. Definitely not ideal, but hopefully
this unblocks you if you run into the same issue.&lt;/p&gt;
&lt;p&gt;I will update this article if I find a better solution. If you have one, please
send me an email.&lt;/p&gt;
</description>
      <pubDate>Sun, 30 Jun 2024 01:21:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/bypass-error-there-are-no-prompts-in-promptfoo/</guid>
    </item>
    <item>
      <title>Use state callbacks in React</title>
      <link>https://seanmcp.com/articles/use-state-callbacks-in-react/</link>
      <description>&lt;p&gt;When you want to update state in React, you have two options: pass the next
value, or pass a callback function that returns the next value.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setState&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Next value&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;reset&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Callback function&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; prev &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To choose correctly, you need to ask if the next state depends on the previous.
If so, choose the callback function. Otherwise, you can pass the next value.&lt;/p&gt;
&lt;p&gt;The reason for this is that React does not update state until the next render.
So if you have multiple references to &lt;code&gt;state&lt;/code&gt; in the callstack, all but the
first will be stale. Here&#39;s a contrived example:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ⚠ Buggy code&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;loginSuccess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; username &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;showLoginModal&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the &lt;code&gt;loginSuccess&lt;/code&gt; function is called, it first sets the &lt;code&gt;username&lt;/code&gt;
property while referencing the current &lt;code&gt;state&lt;/code&gt;. No issues so fare.&lt;/p&gt;
&lt;p&gt;But although &lt;code&gt;setState&lt;/code&gt; has executed, &lt;code&gt;state&lt;/code&gt; will not change until the next
render. So when the second &lt;code&gt;setState&lt;/code&gt; is called, it references the stale &lt;code&gt;state&lt;/code&gt;
value which does not include the updated &lt;code&gt;username&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The final &lt;code&gt;state&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; what we want:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// We wanted this to be updated&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;showLoginModal&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can try to avoid this by avoiding multiple &lt;code&gt;setState&lt;/code&gt; calls in the same
stack. But as your application grows, you will inevitably run into this issue.
And in my experience it&#39;s not an easy bug to track down.&lt;/p&gt;
&lt;p&gt;The better solution is to &lt;strong&gt;use the callback function every time you need to
reference the previous state&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ❌ setState(count + 1)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ❌ setState(items.filter((item) =&gt; item.id !== id))&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ❌ setState(!isEnabled)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;isEnabled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isEnabled&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ❌ setState({ ...user, username: &quot;seanmcp&quot; })&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;seanmcp&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will ensure that every &lt;code&gt;setState&lt;/code&gt; call references the latest state,
regardless of where it is in the callstack.&lt;/p&gt;
</description>
      <pubDate>Fri, 28 Jun 2024 01:17:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/use-state-callbacks-in-react/</guid>
    </item>
    <item>
      <title>VIVO sit/stand desk</title>
      <link>https://seanmcp.com/articles/vivo-sit-stand-desk/</link>
      <description>&lt;p&gt;In 2021 I purchased a
&lt;a href=&quot;https://vivo-us.com/collections/most-popular-standing-desks/products/desk-kit-b04b?variant=33285162795107&quot;&gt;43&amp;quot; VIVO sit/stand desk&lt;/a&gt;
from Amazon. It has served me well for the last few years, but I have
encountered a few issues and solutions that I want to log here.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;desktop-rocks-back-and-forth&quot; tabindex=&quot;-1&quot;&gt;Desktop rocks back and forth&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/vivo-sit-stand-desk/#desktop-rocks-back-and-forth&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Desktop rocks back and forth”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;When the allen bolts that hold the desktop to the frame are too loose, then the
desktop will rock back and forth with normal use. This is particularly
noticeable when you are leaning on the desk, but also when writing or typing.&lt;/p&gt;
&lt;p&gt;To fix this, I&#39;ve found that tightening the bolts with an allen wrench prevents
the rocking. However, over-tightening results in the paint chipping around the
bolt holes and slight deformations of the metal. Be careful and only tighten as
much as necessary.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;desktop-squeaks-under-pressure&quot; tabindex=&quot;-1&quot;&gt;Desktop squeaks under pressure&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/vivo-sit-stand-desk/#desktop-squeaks-under-pressure&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Desktop squeaks under pressure”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;This one was maddening: whenever I applied the slightest pressure on the desktop
it would squeak. Some days it was so bad that every keystroke prompted a small
squeak.&lt;/p&gt;
&lt;p&gt;Loosening the allen bolts that hold the desktop to the frame fixed this issue
but caused the rocking issue mentioned above.&lt;/p&gt;
&lt;p&gt;To fix this, I purchased nylon washers from the hardware store and placed them
in-between the frame and the brackets holding the desktop&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/vivo-sit-stand-desk/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. With those in
place the the allen bolts tightened, the squeaking has stopped.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;modifications&quot; tabindex=&quot;-1&quot;&gt;Modifications&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/vivo-sit-stand-desk/#modifications&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Modifications”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Added an
&lt;a href=&quot;https://www.ikea.com/us/en/p/signum-cable-management-horizontal-silver-color-30200253/&quot;&gt;IKEA Signum cable organizer&lt;/a&gt;
to the bottom of the desktop&lt;/li&gt;
&lt;li&gt;Added a generic clear acrylic headphone hanger to the bottom of the desktop&lt;/li&gt;
&lt;/ul&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Don&#39;t be like me: make sure to clear the desktop before you do this &lt;a href=&quot;https://seanmcp.com/articles/vivo-sit-stand-desk/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Thu, 27 Jun 2024 18:09:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/vivo-sit-stand-desk/</guid>
    </item>
    <item>
      <title>Simplify event delegation with the Element.closest method</title>
      <link>https://seanmcp.com/articles/simplify-event-delegation-with-the-element-closest-method/</link>
      <description>&lt;p&gt;Let&#39;s say you have a list of buttons and want to perform an action when one is
selected. A solution is to add an event listener to each button with a reference
from querying or creating the button.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; buttons &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
buttons&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Clicked:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; button&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a small number of buttons, this is fine. But as the number of buttons grows
or if they are added and removed dynamically, then this solution grows
inefficient and fiddly&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/simplify-event-delegation-with-the-element-closest-method/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Another option is to delegate the event handling to a parent element. Since most
events bubble in JavaScript, an event that is fired on the &lt;code&gt;button&lt;/code&gt; child will
trigger the listener callback for the parent.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of a delegated event listener in a counter where a parent
contains buttons that increment by different amounts:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; parent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#increment-buttons&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  count &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;increment&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I like this pattern because it enables you to add buttons declaratively in HTML
instead of imperatively in JavaScript. That said, the code above is brittle. If
you add additional markup to the buttons, like an &lt;code&gt;svg&lt;/code&gt; icon or a &lt;code&gt;span&lt;/code&gt;, then
the &lt;code&gt;e.target&lt;/code&gt; will refer to that element instead of the &lt;code&gt;button&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To resolve this, we can
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/closest&quot;&gt;use the &lt;code&gt;Element.closest&lt;/code&gt; method&lt;/a&gt;
to walk up the DOM tree to find the nearest element that matches a selector.
&lt;code&gt;Element.closest&lt;/code&gt; checks the element first before moving to the parent, so we
can use it in our event listener to find the button:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; parent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#increment-buttons&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button[data-increment]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    count &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;increment&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Other rendering logic...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we are free to add children elements to our buttons without breaking our
event listener.&lt;/p&gt;
&lt;p&gt;Event delegation is a useful pattern to simplify situations like this where you
have many descendant elements that need similar event listeners. But if you
tried to route all of your events through a single parent like the &lt;code&gt;document&lt;/code&gt;,
it would grow inefficient and unwieldy too&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/simplify-event-delegation-with-the-element-closest-method/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Reach for the best tool for the job, and when you choose event delegation:
remember &lt;code&gt;Element.closest&lt;/code&gt;.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;You have more event listeners in memory and need to manage them all
manually. &lt;a href=&quot;https://seanmcp.com/articles/simplify-event-delegation-with-the-element-closest-method/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;You need to call &lt;code&gt;Element.closest&lt;/code&gt; and add conditional logic for every event
interaction. &lt;a href=&quot;https://seanmcp.com/articles/simplify-event-delegation-with-the-element-closest-method/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Wed, 12 Jun 2024 01:31:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/simplify-event-delegation-with-the-element-closest-method/</guid>
    </item>
    <item>
      <title>Align content in Markdown tables</title>
      <link>https://seanmcp.com/articles/align-content-in-markdown-tables/</link>
      <description>&lt;p&gt;You can set the &lt;code&gt;align&lt;/code&gt; attribute on a table column in Markdown by using a colon
in the header row separator.&lt;/p&gt;
&lt;p&gt;A typical table looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token table&quot;&gt;&lt;span class=&quot;token table-header-row&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; A   &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; B   &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; C   &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token table-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token table-data-rows&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To align the content, add colons to the separator row--&lt;code&gt;:-&lt;/code&gt; for left, &lt;code&gt;:-:&lt;/code&gt; for
center, and &lt;code&gt;-:&lt;/code&gt; for right:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token table&quot;&gt;&lt;span class=&quot;token table-header-row&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt; A    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt;   B    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-header important&quot;&gt;     C &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token table-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:---&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:----:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;----:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token table-data-rows&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; Left &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; Center &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token table-data&quot;&gt; Right &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That Markdown will render a &lt;code&gt;table&lt;/code&gt; with the &lt;code&gt;align&lt;/code&gt; attribute set on the header
and body cells:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;A&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;B&lt;/th&gt;
&lt;th style=&quot;text-align:right&quot;&gt;C&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Left&lt;/td&gt;
&lt;td style=&quot;text-align:center&quot;&gt;Center&lt;/td&gt;
&lt;td style=&quot;text-align:right&quot;&gt;Right&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;https://www.markdownguide.org/extended-syntax/#tables&quot;&gt;Read more about Markdown tables&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Fri, 07 Jun 2024 10:47:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/align-content-in-markdown-tables/</guid>
    </item>
    <item>
      <title>CSS nesting is (almost) ready</title>
      <link>https://seanmcp.com/articles/css-nesting-is-almost-ready/</link>
      <description>&lt;p&gt;I&#39;ve been hearing a lot about CSS nesting, but I figured that it was still years
away from being ready for use even on a site like this.&lt;/p&gt;
&lt;p&gt;But a quick check of &lt;a href=&quot;https://caniuse.com/css-nesting&quot;&gt;Can I Use&lt;/a&gt; shows that it
is ready in all major browsers. Even more if you make sure to use the &lt;code&gt;&amp;amp;&lt;/code&gt;
nesting selector.&lt;/p&gt;
&lt;p&gt;Try it out for yourself:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://seanmcp.com/articles/css-nesting-is-almost-ready&quot; style=&quot;display: none&quot;&gt;View this
interactive on seanmcp.com&lt;/a&gt;&lt;/p&gt;
&lt;style style=&quot;background-color: var(--inline-code-background); color: var(--inline-code-color); display:block; font-family: var(--mono-font); padding: 1em; white-space: preserve;&quot; contenteditable=&quot;&quot;&gt;main {
    &amp; time {
        display: block;
        text-align: center;
    }

    &amp; h1 {
        color: red;
    }

    &amp; p:first-of-type {
        font-style: italic;
    }

    &amp; p {
        &amp; code {
            outline: 2px dotted currentColor;
        }
    }

    &amp; style + p:has(em) {
        border: 1px solid currentColor;
        padding: 1em;
    }

    &amp; p:last-child {
        text-decoration: double underline;
    }
}
&lt;/style&gt;
&lt;p&gt;So should you start using CSS nesting today? Probably not. But it is &lt;em&gt;almost&lt;/em&gt;
ready, and that&#39;s exciting. Variables and nesting are the two features that
would still draw me to a preprocessor like Sass or Less. We&#39;ve had native custom
properties for years, and now we are so close to being able to use nesting.&lt;/p&gt;
&lt;p&gt;Exciting times!&lt;/p&gt;
</description>
      <pubDate>Tue, 28 May 2024 24:50:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/css-nesting-is-almost-ready/</guid>
    </item>
    <item>
      <title>Looking over the fence at Eleventy</title>
      <link>https://seanmcp.com/articles/looking-over-the-fence-at-eleventy/</link>
      <description>&lt;p&gt;First of all: I&#39;m happy with Astro. It&#39;s an exciting project that provides the
tools necessary to build websites in the way I want to build them. The future is
bright for Astro.&lt;/p&gt;
&lt;p&gt;But... I still find myself looking at alternatives.
&lt;a href=&quot;https://seanmcp.com/articles/astro-and-release-velocity/&quot;&gt;I&#39;ve written previously about Astro&#39;s relentless releases&lt;/a&gt;,
and it continues to be a source of stress for me.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/looking-over-the-fence-at-eleventy/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; Every other week it&#39;s a
fresh release and reminder that I am behind. Are there alternatives that provide
me some of the same features without the release cadence?&lt;/p&gt;
&lt;p&gt;Thanks to the recent &amp;quot;International Symposium On Making Web Sites Real Good&amp;quot;
conference and its positive reviews, Eleventy has caught my eye again. Robin
Rendle&#39;s
&lt;a href=&quot;https://buttondown.email/cascade/archive/020-notes-on-the-blog/&quot;&gt;recent experience returning to Eleventy&lt;/a&gt;
was insightful. Once upon a time this site was previously built with Eleventy,
and I liked it too... until I didn&#39;t.&lt;/p&gt;
&lt;p&gt;Eleventy was fast and focused, but the lack of opinions meant that you could
easily architect yourself into a corner. I was so bogged down with Nunjucks
templates, filters, and shortcodes in the end that I gave up and rebuilt in
Astro.&lt;/p&gt;
&lt;p&gt;That said, I still admire what Zach Leatherman is doing with Eleventy. and the
community that he is building. I like the ethos, and that gives me confidence in
where the project will be in 3-5 years. Can I say the same for Astro?&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/looking-over-the-fence-at-eleventy/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I&#39;m not going to re-write this site. But I think I&#39;m going to
&lt;a href=&quot;https://seanmcp.com/resources/getting-started-with-eleventy/&quot;&gt;reach for Eleventy&lt;/a&gt; the next time
I&#39;m building a simple or long-lived website. If all I need is a way to generate
a bunch of HTML with linked CSS and JavaScript, Eleventy seems like the better
option of the two.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;At the time of writing, I am five minor releases behind and counting. &lt;a href=&quot;https://seanmcp.com/articles/looking-over-the-fence-at-eleventy/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I think the answer is no. They have received venture capital and need to
find some way to make a return on that investment. Since I&#39;m not a paying
customer, I don&#39;t have great confidence that the project will grow in the
direction that meets my needs. &lt;a href=&quot;https://seanmcp.com/articles/looking-over-the-fence-at-eleventy/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 27 May 2024 18:43:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/looking-over-the-fence-at-eleventy/</guid>
    </item>
    <item>
      <title>Getting started with Eleventy</title>
      <link>https://seanmcp.com/articles/getting-started-with-eleventy/</link>
      <description>&lt;p&gt;Eleventy has &lt;a href=&quot;https://www.11ty.dev/docs/&quot;&gt;&amp;quot;Get Started&amp;quot; documentation&lt;/a&gt; that
shows you how to get from a single markdown file to a built site. That is a nice
&amp;quot;proof of idea&amp;quot;, but I haven&#39;t found it to be a helpful way to actually get
started with Eleventy. This garden aims to be a better guide for building a
simple Eleventy site from scratch.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;setup&quot; tabindex=&quot;-1&quot;&gt;Setup&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#setup&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Setup”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Create a new directory for your project: &lt;code&gt;mkdir getting-started-eleventy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In that directory, initialize a new project: &lt;code&gt;npm init -y&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Install Eleventy: &lt;code&gt;npm install @11ty/eleventy@canary --save-exact&lt;/code&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; scripts to your &lt;code&gt;package.json&lt;/code&gt;:&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;dev&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eleventy --serve&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;eleventy&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At this point you&#39;re probably tempted to run the &lt;code&gt;dev&lt;/code&gt; script, but hold off for
a little bit. We need to add some configuration to keep the project organized.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;configuration&quot; tabindex=&quot;-1&quot;&gt;Configuration&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#configuration&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Configuration”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Create a new &lt;code&gt;src&lt;/code&gt; directory: &lt;code&gt;mkdir src&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create your first markdown file: &lt;code&gt;echo &amp;quot;# Hello, world!&amp;quot; &amp;gt; src/index.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;.eleventy.js&lt;/code&gt; file in the root directory: &lt;code&gt;touch .eleventy.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add the following configuration to &lt;code&gt;.eleventy.js&lt;/code&gt;:&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dist&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Or whatever build directory you prefer&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This configuration will tell Eleventy to look for source files in the &lt;code&gt;src/&lt;/code&gt;
directory, and skip generating webpages for your project &lt;code&gt;README.md&lt;/code&gt;. You can
stick with the default &lt;code&gt;_site/&lt;/code&gt; output directory, but I like explicitly setting
the output directory so that you know where they&#39;re going.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Add a &lt;code&gt;.gitignore&lt;/code&gt; file to the root directory:&lt;pre&gt;&lt;code&gt;node_modules/
dist/ # Or whatever build directory you chose in .eleventy.js
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At this point, you can run &lt;code&gt;npm run build&lt;/code&gt; to generate your site. You should see
a single &lt;code&gt;index.html&lt;/code&gt; file in your build directory. But your site is probably
going to need more than HTML, so we&#39;ll configure Eleventy to handle assets.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;assets&quot; tabindex=&quot;-1&quot;&gt;Assets&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#assets&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Assets”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new &lt;code&gt;public/&lt;/code&gt; directory in the root of your project: &lt;code&gt;mkdir public&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a line to your &lt;code&gt;.eleventy.js&lt;/code&gt; configuration to copy the &lt;code&gt;public/&lt;/code&gt;
directory to the build directory:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPassthroughCopy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will copy all of the files within your &lt;code&gt;public/&lt;/code&gt; directory to the root
of the build directory. You can test this by adding a CSS files to the
&lt;code&gt;public/&lt;/code&gt; directory and running &lt;code&gt;npm run build&lt;/code&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;echo &amp;quot;body { font-family: system-ui }&amp;quot; &amp;gt; public/styles.css
npm run build
ls dist
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see &lt;code&gt;styles.css&lt;/code&gt; in the build directory, but the styles won&#39;t apply
because the CSS files isn&#39;t linked to the HTML. To do that, we&#39;ll need to create
a layout.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;layouts&quot; tabindex=&quot;-1&quot;&gt;Layouts&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#layouts&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Layouts”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Eleventy supports a bunch of different templating languages for layouts. I don&#39;t
like any of them&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;, but JavaScript is good enough.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a new &lt;code&gt;_includes/&lt;/code&gt; directory in &lt;code&gt;src/&lt;/code&gt;: &lt;code&gt;mkdir src/_includes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a new &lt;code&gt;base.11ty.js&lt;/code&gt; file there: &lt;code&gt;touch src/_includes/base.11ty.js&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This will serve as our base layout that includes all the HTML boilerplate. In
that file, add the following:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Base&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;!DOCTYPE html&gt;
      &amp;lt;html lang=&quot;en&quot;&gt;
        &amp;lt;head&gt;
          &amp;lt;meta charset=&quot;UTF-8&quot;&gt;
          &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
          &amp;lt;title&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/title&gt;
          &amp;lt;meta name=&quot;description&quot; content=&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;
            data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metaDescription &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Generic site description&quot;&lt;/span&gt;
          &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&gt;
          &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;/styles.css&quot;&gt;
        &amp;lt;/head&gt;
        &amp;lt;body&gt;
          &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
        &amp;lt;/body&gt;
      &amp;lt;/html&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This layout will render an HTML document with &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;metaDescription&lt;/code&gt;, and
&lt;code&gt;content&lt;/code&gt; properties. Noticed that we&#39;ve now linked the CSS file that we copied
in the &amp;quot;Assets&amp;quot; sections. Now we need to configure our markdown file to use this
layout.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Update your &lt;code&gt;index.md&lt;/code&gt; file to use the layout:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; base.11ty.js
&lt;span class=&quot;token key atrule&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; page.liquid
&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Home
&lt;span class=&quot;token key atrule&quot;&gt;metaDescription&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; The homepage of my site&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;

The &quot;body&quot; of markdown files becomes &lt;span class=&quot;token code-snippet code keyword&quot;&gt;`content`&lt;/span&gt; in layouts.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when you run your build again, you should see your &lt;code&gt;index.html&lt;/code&gt; file with
the additional markup including applied styles.&lt;/p&gt;
&lt;p&gt;When you want to chain a layout in JavaScript, you need to refer to the parent
layout in the &lt;code&gt;class&lt;/code&gt;&#39;s &lt;code&gt;data&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Page&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;base.11ty.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;main&gt;
        &amp;lt;h1&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/h1&gt;
        &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
      &amp;lt;/main&gt;
    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This new &lt;code&gt;Page&lt;/code&gt; layout will render within the &lt;code&gt;Base&lt;/code&gt; layout, giving you the
power of composition when building pages. I typically have a base layout and
then 2-3 other layouts that I use for different types of pages.&lt;/p&gt;
&lt;p&gt;The next thing you&#39;ll probably want are UI &amp;quot;components&amp;quot; that you can reuse
across your site, and for that we&#39;ll turn to Eleventy&#39;s &amp;quot;shortcodes&amp;quot;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;shortcodes&quot; tabindex=&quot;-1&quot;&gt;Shortcodes&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#shortcodes&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Shortcodes”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;You could organize this section however you want. I&#39;m going to show you one way
that works well for smaller projects.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a directory for shortcodes in &lt;code&gt;_includes/&lt;/code&gt;:
&lt;code&gt;mkdir src/_includes/shortcodes&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create your first shortcode file: &lt;code&gt;touch src/_includes/shortcodes/emoji.js&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following to &lt;code&gt;emoji.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/** An accessible emoji shortcode */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;emojiShortcode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;emoji&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; attributes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;role=img&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    label &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;aria-label=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;label&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;aria-hidden=true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;span &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;attributes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;emoji&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the shortcode in your &lt;code&gt;.eleventy.js&lt;/code&gt; config file:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; emojiShortcode &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./src/_includes/shortcodes/emoji&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addShortcode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;emoji&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; emojiShortcode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the new shortcode in your markdown file:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; page.11ty.js
&lt;span class=&quot;token key atrule&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; page.liquid
&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Home&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;

{% emoji &quot;👋&quot; &quot;Waving hand&quot; %} Hi there!&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;
&lt;p&gt;Use the new shortcode in your layout file:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Page&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;base.11ty.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
       &amp;lt;main&gt;
         &amp;lt;h1&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;/h1&gt;
         &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emoji&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;👋&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Waving hand&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; Thanks for visiting!
       &amp;lt;/main&gt;
     &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Build your site and you should see the emoji rendering with the appropriate
markup.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;syntax-highlighting&quot; tabindex=&quot;-1&quot;&gt;Syntax highlighting&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#syntax-highlighting&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Syntax highlighting”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Eleventy will format inline code and code blocks correctly, but you need a
plugin for syntax highlighting.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the official plugin: &lt;code&gt;pnpm i @11ty/eleventy-plugin-syntaxhighlight&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add the plugin to the &lt;code&gt;.eleventy.js&lt;/code&gt; config:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; syntaxHighlight &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@11ty/eleventy-plugin-syntaxhighlight&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPlugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;syntaxHighlight&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Now the generated markup will have token classes. To style those differently,
you can either create your own theme or
&lt;a href=&quot;https://github.com/PrismJS/prism-themes/tree/master&quot;&gt;download a Prism theme&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Link those styles in your base or page template and syntax highlighting will
work for code blocks. (You may want to tweak the styles to apply to inline
code too.)&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;footnotes&quot; tabindex=&quot;-1&quot;&gt;Footnotes&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#footnotes&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Footnotes”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Eleventy does not have an official plugin for markdown footnotes, but the
markdown parser it uses does.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the markdown-it plugin: &lt;code&gt;pnpm i markdown-it markdown-it-footnote&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add the config to &lt;code&gt;.eleventy.js&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; markdownIt &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;markdown-it&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; markdownItFootnote &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;markdown-it-footnote&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setLibrary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;md&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;markdownIt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;markdownItFootnote&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Configure the plugin to meet your needs:
&lt;a href=&quot;https://github.com/markdown-it/markdown-it-footnote?tab=readme-ov-file#customize&quot;&gt;&lt;code&gt;markdown-it-footnote&lt;/code&gt; documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#conclusion&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Conclusion”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;There is a lot more that we could do, but at this point you are definitely
started. With this little bit of organization and configuration, you&#39;re now on
your way to building real sites with Eleventy.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I&#39;m recommending the canary release here because it includes ECMAScript
module support. This is the future of JavaScript and Eleventy, so might as
well get on board now. &lt;a href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I&#39;ve been spoiled by composition patterns in JSX, Svelte, and Astro. I find
it difficult to build UI in the way that my mind wants to think using
templating languages like Nunjucks or Liquid. &lt;a href=&quot;https://seanmcp.com/articles/getting-started-with-eleventy/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 27 May 2024 17:45:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/getting-started-with-eleventy/</guid>
    </item>
    <item>
      <title>ChatGPT 4o isn&#39;t a good researcher yet</title>
      <link>https://seanmcp.com/articles/chatgpt-4o-isnt-a-good-researcher-yet/</link>
      <description>&lt;p&gt;I asked ChatGPT 4o for general recommendations for
&lt;a href=&quot;https://seanmcp.com/articles/astro-and-release-frequency/&quot;&gt;software release frequency&lt;/a&gt;, and it
spouted out some information that seemed generally plausible. I asked it to cite
its sources, and after an internet search it provided three links. I checked all
three, and none of them contained the information that ChatGPT initially
provided.&lt;/p&gt;
&lt;p&gt;I replied with &amp;quot;None of those articles had the guidelines that you cited&amp;quot; and it
responded back with more information and more links. I checked a few of them,
but it was the same as before. They were on the same topic, but the information
that ChatGPT provided was not sourced from those articles.&lt;/p&gt;
&lt;p&gt;I don&#39;t know what I expected, but it&#39;s clear that ChatGPT 4o isn&#39;t a reliable
research assistant yet. It can provide you some common &lt;s&gt;misconceptions&lt;/s&gt;
information, but it isn&#39;t going to point you to a true source consistently.
You&#39;re going to need to research for yourself.&lt;/p&gt;
&lt;p&gt;Use with caution.&lt;/p&gt;
</description>
      <pubDate>Sat, 18 May 2024 01:51:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/chatgpt-4o-isnt-a-good-researcher-yet/</guid>
    </item>
    <item>
      <title>Astro and release velocity</title>
      <link>https://seanmcp.com/articles/astro-and-release-velocity/</link>
      <description>&lt;p&gt;This website is built with &lt;a href=&quot;https://astro.build&quot;&gt;Astro&lt;/a&gt;, and overall I&#39;ve been
happy with my choice. The framework model makes sense to me, and I really enjoy
using their templating language for building UI. If I were to start over today,
I would still choose Astro.&lt;/p&gt;
&lt;p&gt;But I&#39;ve had an unsettled feeling about Astro and this site, and I think I&#39;ve
finally put my finger on it: Astro is moving too quickly. It feels like every
few weeks they&#39;re putting out a new version with new features and new patterns
to build new websites.&lt;/p&gt;
&lt;p&gt;And as exciting as that is (I&#39;m sure the maintainers are thrilled to be able to
ship new things so quickly), it&#39;s overwhelming for me as a user. I feel like I&#39;m
always behind because I am. I updated the Astro dependencies on this site two
months ago, and I&#39;m already four minor versions behind. That&#39;s two minor
versions per month!&lt;/p&gt;
&lt;p&gt;Now full credit should go to the Astro team for working to make updates
relatively painless. I haven&#39;t encountered any particularly difficult breaking
changes, and they have tooling that helps make the process simpler. But a simple
process is still a process, and it&#39;s one that users have to do a lot to keep
their Astro sites up to date.&lt;/p&gt;
&lt;p&gt;I know that no one is forcing me keep my dependencies on latest; that pressure
is internal. But it&#39;s real, and it impacts how I feel about working with Astro.&lt;/p&gt;
&lt;p&gt;Given two identical frameworks, my preference would be for one that updated
&lt;em&gt;regularly&lt;/em&gt; but less frequently. Quarterly or even twice-yearly updates would be
perfect (patches excluded). Enough to keep you thinking about updating
dependencies but not so often that you&#39;re always behind.&lt;/p&gt;
&lt;p&gt;Sadly for me, that isn&#39;t the reality with Astro. Is that enough to drive me to
choose a different framework? No. But release velocity was not something I
considered when choosing Astro. Now with a little more experience it is
something that I will think about in the future.&lt;/p&gt;
</description>
      <pubDate>Sat, 18 May 2024 01:12:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/astro-and-release-velocity/</guid>
    </item>
    <item>
      <title>Render and effect call order in React</title>
      <link>https://seanmcp.com/articles/render-and-effect-call-order-in-react/</link>
      <description>&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;: Let&#39;s say I have a React tree like this:&lt;/p&gt;
&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Parent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Parent render&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Parent effect&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useLayoutEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Parent layout effect&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Child&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Child&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Child render&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Child effect&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;useLayoutEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Child layout effect&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createRoot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Parent&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What order would you expect the logs to fire in? If you were like me, you&#39;d
probably have some mental model of how React works and be able to make an
educated guess. But I was wrong.&lt;/p&gt;
&lt;p&gt;Then I asked this question to a handful of seasoned React developers, and they
all got it wrong.&lt;/p&gt;
&lt;p&gt;Because the real answer is unexpected:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Parent render
Child render
Child layout effect
Parent layout effect
Child effect
Parent effect
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Try it yourself&lt;/strong&gt;:
&lt;a href=&quot;https://stackblitz.com/edit/vitejs-vite-7n9w8p?file=src%2Fmain.tsx&quot;&gt;Here&#39;s a StackBlitz in case you don&#39;t believe me.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Attempting an explanation&lt;/strong&gt;: When rendering a tree, React calls the components
from the top of the tree downward. So because &lt;code&gt;Parent&lt;/code&gt; is at the top of the
tree, its render log is called before &lt;code&gt;Child&lt;/code&gt;. So far, so good.&lt;/p&gt;
&lt;p&gt;Effects are a different story. React effectively queues effects from the bottom
of the tree upward, so &lt;code&gt;Child&lt;/code&gt;&#39;s effects are called before &lt;code&gt;Parent&lt;/code&gt;&#39;s. Plus
there is the additional layer that &lt;code&gt;useLayoutEffect&lt;/code&gt; is called before
&lt;code&gt;useEffect&lt;/code&gt; (which, to be fair, does make sense but is one more thing to think
about).&lt;/p&gt;
&lt;p&gt;I ran into this issue at work when a child had code running on render that was
occurring before the parent&#39;s &lt;code&gt;useLayoutEffect&lt;/code&gt; ran. There were several layers
of components between the two, and finding the cause was not fun.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: I don&#39;t expect you or me or anyone else to remember this order.
But if you can remember that the order is unexpected, then that will put you on
the right path.&lt;/p&gt;
</description>
      <pubDate>Sat, 18 May 2024 24:43:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/render-and-effect-call-order-in-react/</guid>
    </item>
    <item>
      <title>Manage your photo archive</title>
      <link>https://seanmcp.com/articles/manage-your-photo-archive/</link>
      <description>&lt;p&gt;A coworker at Khan Academy shared some advice (apparently secondhand from the
New York Times) for managing your ever-growing photo archive:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Every day open your photos app&lt;/li&gt;
&lt;li&gt;Search for the day&#39;s date&lt;/li&gt;
&lt;li&gt;Review your old photos from that day&lt;/li&gt;
&lt;li&gt;Delete ones you don&#39;t need anymore&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My first thought was &amp;quot;That&#39;s brilliant!&amp;quot; It&#39;s a low lift but once the habit is
established it ensures that you address every day of the year.&lt;/p&gt;
&lt;p&gt;The first day I tried it, I found this photo from 2017 when I was still
teaching:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/old-photo.jpg&quot; alt=&quot;Directions for a writing (?) assignment written on a whiteboard&quot;&gt;&lt;/p&gt;
&lt;p&gt;I have no memory of this day or what I was expecting the students to do, so I
deleted it. One less photo in the archive!&lt;/p&gt;
&lt;p&gt;With strategies like this, we can reduce the amount of junk data that we all
have hanging around on someone else&#39;s server.&lt;/p&gt;
</description>
      <pubDate>Thu, 09 May 2024 10:36:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/manage-your-photo-archive/</guid>
    </item>
    <item>
      <title>Measuring and cutting</title>
      <link>https://seanmcp.com/articles/measuring-and-cutting/</link>
      <description>&lt;p&gt;I learned “measure twice, cut once” while working with my dad. He probably
learned it from his dad and him from his dad. It’s good advice, but in an issue
of &lt;a href=&quot;https://frontendatscale.com/issues/16/&quot;&gt;Frontend at Scale&lt;/a&gt; Maxi Ferreira
suggests that it might not apply neatly to software engineering:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[S]oftware is different, and trying to apply this piece of advice to planning,
designing, and writing applications can sometimes do more harm than good.&lt;/p&gt;
&lt;p&gt;Measuring twice (i.e. considering all possible options and coming up with
the &lt;em&gt;perfect&lt;/em&gt; design or architecture before writing a single line of code) is
not the most effective way to build software. That’s the waterfall approach,
and we know it doesn’t work.&lt;/p&gt;
&lt;p&gt;Instead, we can use the flexibility of software to our advantage and flip the
woodworker’s advice on its head. We can measure once, decide quickly, and cut
as many times as needed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When your materials are (close to) free, you don’t need to spend the extra time
up front getting all of measurements perfect. Instead, get ship something and
spend that time iterating.&lt;/p&gt;
&lt;p&gt;He expands on the idea more in the article. Give it a read and let me know what
you think.&lt;/p&gt;
</description>
      <pubDate>Wed, 24 Apr 2024 17:24:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/measuring-and-cutting/</guid>
    </item>
    <item>
      <title>Create a custom search for a static site</title>
      <link>https://seanmcp.com/articles/create-a-custom-search-for-a-static-site/</link>
      <description>&lt;p&gt;There are out-of-the-box solutions for searching on a static site. I previously
used &lt;a href=&quot;https://pagefind.app/&quot;&gt;Pagefind&lt;/a&gt; for this site which remains a great
option. But if you want fully control of the behavior and appearance of your
search feature, then you might have to build your own.&lt;/p&gt;
&lt;p&gt;After thinking through how I wanted to use a search feature, I came up with
these acceptance criteria:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Query and filter by type, year, and tag&lt;/strong&gt;: I want to be able to view all
Articles from 2023 tagged JavaScript with the text “class”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fuzzy search&lt;/strong&gt;: Before Pagefind I had a search that used strict string
matching, but the experience was poor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;URL-powered&lt;/strong&gt;: I want to use it as a custom search engine in the browser and
be able to link directly to filtered search results.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With those criteria established, I could move on to designing and building the
solution.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;Solution&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-custom-search-for-a-static-site/#solution&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Solution”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Without going into too many details about
&lt;a href=&quot;https://github.com/SeanMcP/seanmcp.com/blob/bf0792380cc13f6c3b79d30121a78c9c5548f225/src/pages/search.astro&quot;&gt;how I accomplished this in Astro&lt;/a&gt;,
here are the high-level steps I followed to build a custom search:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Gather all of my content into a normalized array:&lt;/strong&gt; As I’ve written
previously,
&lt;a href=&quot;https://www.seanmcp.com/articles/normalizing-data-is-a-good-idea/&quot;&gt;normalizing data is a good idea&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expose the data to client-side JavaScript:&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;Astro has a helpful &lt;code&gt;define:vars&lt;/code&gt; directive for this, but your static-site
generator has some kind of solution for hand off data with a &lt;code&gt;script&lt;/code&gt; tag.&lt;/li&gt;
&lt;li&gt;The important part for me was to avoid network requests for the content
data; I wanted this to be available at build time.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In JS sync HTML with URL:&lt;/strong&gt; Read the search parameters and then update the
in-page form elements with the data. For this solution, the URL is the source
of truth.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create a function to search and render:&lt;/strong&gt; I wanted the results to render on
load and whenever there was a change to the search form. By encapsulating
that logic in a function, I was able to call it whenever I wanted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use &lt;a href=&quot;https://www.fusejs.io/&quot;&gt;Fuse.js&lt;/a&gt; to search through content:&lt;/strong&gt; This is
the first time I’ve used Fuse and it was awesome. I added it from a CDN with
a script tag, and it worked without any issues.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Render:&lt;/strong&gt; Take the results from Fuse and add some markup to an &lt;code&gt;output&lt;/code&gt;
element.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add event listeners for &lt;code&gt;change&lt;/code&gt;, &lt;code&gt;input&lt;/code&gt;, and &lt;code&gt;submit&lt;/code&gt;:&lt;/strong&gt; These were all
added to the &lt;code&gt;form&lt;/code&gt; element to a) sync URL with form state, and b) render
updated results.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can view the finished product at
&lt;a href=&quot;https://seanmcp.com/search&quot;&gt;seanmcp.com/search&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://seanmcp.com/search/?q=JavaScript&quot;&gt;seanmcp.com/search/?q=JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://seanmcp.com/search/?type=note&quot;&gt;seanmcp.com/search/?type=note&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://seanmcp.com/search/?tag=A+Few+Things&quot;&gt;seanmcp.com/search/?tag=A+Few+Things&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://seanmcp.com/search/?year=2024&quot;&gt;seanmcp.com/search/?year=2024&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://seanmcp.com/search/?q=class&amp;amp;type=article&amp;amp;year=2023&amp;amp;tag=JavaScript&quot;&gt;seanmcp.com/search/?q=class&amp;amp;type=article&amp;amp;year=2023&amp;amp;tag=JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;lessons-learned&quot; tabindex=&quot;-1&quot;&gt;Lessons learned&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-custom-search-for-a-static-site/#lessons-learned&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Lessons learned”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Pushing search parameters to the URL without reloading is easier than I
thought. I really like the idea of using the URL as the state for a feature
like this.&lt;/li&gt;
&lt;li&gt;The default &lt;code&gt;select[multiple]&lt;/code&gt; UI is difficult to design around. I ended up
limiting the filters to a single selection because I couldn’t find a layout
that I liked with multiple.&lt;/li&gt;
&lt;li&gt;Fuse.js was a delight, and I look forward to more opportunities to use it.&lt;/li&gt;
&lt;li&gt;I thought that I would need to debounce changes from the form, but in my
testing it handled individual keypresses without any issue.&lt;/li&gt;
&lt;li&gt;Astro will scope styles for you, but you can only reference elements that are
currently in the file. This is a problem when you will be building a UI with
client JavaScript. Thankfully Astro works with &lt;code&gt;template&lt;/code&gt;s, so you can style a
sample response element and style it without resorting to &lt;code&gt;:global()&lt;/code&gt; calls.&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Fri, 22 Mar 2024 19:08:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/create-a-custom-search-for-a-static-site/</guid>
    </item>
    <item>
      <title>Fix missing Astro files on GitHub pages</title>
      <link>https://seanmcp.com/articles/fix-missing-astro-files-on-github-pages/</link>
      <description>&lt;p&gt;I&#39;m in the middle of a long project to migrate my projects from Netlify to
GitHub pages. I was working on the GitHub actions for
&lt;a href=&quot;https://shama.seanmcp.com&quot;&gt;an Astro project&lt;/a&gt; and noticed that most of the CSS
files were missing from the assets directory.&lt;/p&gt;
&lt;p&gt;When I built the project locally, I saw the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_book_.95a15f93.css
_book_.ef58a27b.css
_chapter_.02b05af9.css
index.3e3ecbbf.css
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;index.3e3ecbbf.css&lt;/code&gt; file was the only CSS one that was successfully
deployed. That led me to think that there was something about the underscore
prefix that was causing the other files to be ignored.&lt;/p&gt;
&lt;p&gt;GitHub Pages uses Jekyll behind the scenes, even if your site doesn&#39;t use it.
And
&lt;a href=&quot;https://github.com/jekyll/jekyll/issues/55&quot;&gt;Jekyll ignores files and directories that start with an underscore&lt;/a&gt;.
So the solution is to tell GitHub to skip Jekyll processing of your build
directory with a &lt;code&gt;.nojekyll&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;In the GitHub Action for the Astro project, I added the following line to the
build step:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;touch dist/.nojekyll&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that was added, all of the generated CSS files were successfully deployed
to GitHub Pages.&lt;/p&gt;
&lt;p&gt;There is also an
&lt;a href=&quot;https://github.com/withastro/action&quot;&gt;official action for Astro projects&lt;/a&gt; that
probably handles that for you.&lt;/p&gt;
</description>
      <pubDate>Wed, 20 Mar 2024 01:12:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-missing-astro-files-on-github-pages/</guid>
    </item>
    <item>
      <title>Create a useIsOnline React hook</title>
      <link>https://seanmcp.com/articles/create-a-use-is-online-react-hook/</link>
      <description>&lt;p&gt;There are two browser features that enable you to detect an internet connection
with JavaScript:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The Navigator interface&#39;s &lt;code&gt;onLine&lt;/code&gt; property for the current state&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;online&lt;/code&gt; and &lt;code&gt;offline&lt;/code&gt; events for state changes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By combining these, we can create a custom React hook that tells us if the
browser is currently online.&lt;/p&gt;
&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Check if window is available&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; maybeWindow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; window &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;undefined&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useIsOnline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;isOnline&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setIsOnline&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Read onLine value from navigator if available, otherwise fallback to true&lt;/span&gt;
    maybeWindow&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;onLine &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Add event listeners on mount&lt;/span&gt;
    maybeWindow&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;online&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setIsOnline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    maybeWindow&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;offline&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setIsOnline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Remove event listeners on unmount&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      maybeWindow&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;online&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setIsOnline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      maybeWindow&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;offline&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setIsOnline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// Return the online status&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; isOnline&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can use this hook to display a banner when the user is running our app and
then goes offline:&lt;/p&gt;
&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; isOnline &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useIsOnline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isOnline &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;alert&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
                    You are offline. Changes will be synced when you reconnect.
                &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    )
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In newer versions of React you can
&lt;a href=&quot;https://github.com/uiwjs/react-use-online&quot;&gt;use a hook like &lt;code&gt;useOnline&lt;/code&gt;&lt;/a&gt; which
depends on
&lt;a href=&quot;https://react.dev/reference/react/useSyncExternalStore&quot;&gt;&lt;code&gt;useSyncExternalStore&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Tue, 19 Mar 2024 19:35:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/create-a-use-is-online-react-hook/</guid>
    </item>
    <item>
      <title>Fix static file endpoints after Astro v4 upgrade</title>
      <link>https://seanmcp.com/articles/fix-static-file-endpoints-after-astro-v4-upgrade/</link>
      <description>&lt;p&gt;Yesterday I
&lt;a href=&quot;https://seanmcp.com/articles/upgrading-from-astro-v2-to-v4&quot;&gt;upgraded to Astro v4 without any issues&lt;/a&gt;,
but this morning I noticed that my RSS feed was broken.&lt;/p&gt;
&lt;p&gt;I have two static file endpoints that generate a file at build time, one for RSS
and the other for a webfinger. Both of these had two issues highlighted after
the upgrade:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The files did not export a &lt;code&gt;GET&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;The files did not return a &lt;code&gt;Response&lt;/code&gt; or &lt;code&gt;Promise&amp;lt;Response&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first issue was resolved by capitalizing the previously-valid &lt;code&gt;get&lt;/code&gt; function
to &lt;code&gt;GET&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The second issue required an update to the &lt;code&gt;@astrojs/rss&lt;/code&gt; dependency which now
returns a &lt;code&gt;Promise&amp;lt;Response&amp;gt;&lt;/code&gt;. The webfinger endpoint is custom, but all I
needed to do was wrap my return value with a &lt;code&gt;Response&lt;/code&gt; object:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Before&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// After&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The webfinger issue is easy to miss (and nonconsequential), but I should have
verified that the RSS feed was working before shipping the upgrade. Lessons
learned!&lt;/p&gt;
</description>
      <pubDate>Tue, 19 Mar 2024 10:03:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-static-file-endpoints-after-astro-v4-upgrade/</guid>
    </item>
    <item>
      <title>Why Microsoft Edge?</title>
      <link>https://seanmcp.com/articles/why-microsoft-edge/</link>
      <description>&lt;p&gt;I like trying out new browsers and try to avoid being tethered to one for too
long. But ever since its switch to Chromium, I find myself coming back to
Microsoft Edge.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Powered by Chromium&lt;/strong&gt;: I have issues with recent releases of Chrome, but
now that Edge is powered by the same underlying technology I don&#39;t need to
choose.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Size conscientious&lt;/strong&gt;: Screen real estate is precious, and Edge is the only
cross-platform browser that cares about conserving it. The combination of
vertical tabs and minimal UI makes it the clear winner for smaller screens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Customizable UI&lt;/strong&gt;: Chrome has started adding buttons to the toolbar that
you can&#39;t remove. Edge allows you to decide what icons make sense for you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unobtrusive AI&lt;/strong&gt;: I don&#39;t use Copilot features often, but it&#39;s there when I
need it and out-of-the-way when I don&#39;t.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DevTools improvements&lt;/strong&gt;: I like the vertical activity bar and the built-in
accessibility checks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you haven&#39;t tried the new Edge, I recommend giving it a look.&lt;/p&gt;
</description>
      <pubDate>Wed, 06 Mar 2024 17:59:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/why-microsoft-edge/</guid>
    </item>
    <item>
      <title>Switching from Ubuntu to Linux Mint</title>
      <link>https://seanmcp.com/articles/switching-from-ubuntu-to-linux-mint/</link>
      <description>&lt;p&gt;Ubuntu was running slow on my old personal laptop. Previously I had turned to
Lubuntu, but I read online that Linux Mint has slighly better performance on
low-powered devices. So with a free morning I decided to give that a go.&lt;/p&gt;
&lt;p&gt;Setup steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Customized the colors and wallpaper&lt;/li&gt;
&lt;li&gt;Switched trackpad scroll from &amp;quot;Reversed&amp;quot; to normal (&lt;em&gt;i.e.&lt;/em&gt; down goes down)&lt;/li&gt;
&lt;li&gt;Installed some key programs with Software Manager&lt;/li&gt;
&lt;li&gt;Removed some bundled software that I won&#39;t need&lt;/li&gt;
&lt;li&gt;Set up a custom search engine in the browser&lt;/li&gt;
&lt;li&gt;Installed git with &lt;code&gt;apt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Installed Node with &lt;code&gt;nvm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set up SSH for GitHub&lt;/li&gt;
&lt;li&gt;Cloned this repo and started writing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;First impressions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It seems to run faster than Ubuntu&lt;/li&gt;
&lt;li&gt;It generally looks good (though I&#39;m not sold on the &amp;quot;LM&amp;quot; icon)&lt;/li&gt;
&lt;li&gt;The window management is nice&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I first installed VS Code with Software Manager, but 1) the terminal was not
loading the correct shell, and 2) the icon was non standard. I downloaded the
&lt;code&gt;.deb&lt;/code&gt; directly from VS Code and installed to fix those problems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Open questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How can I get an emoji picker?&lt;/li&gt;
&lt;li&gt;How do I configure the panel clock to use 12-hour time?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notes on improving the process for me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I haven&#39;t setup settings sync for VS Code, and getting everything running from
scratch isn&#39;t fun. Figure out how to do that for the future.&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Wed, 06 Mar 2024 17:24:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/switching-from-ubuntu-to-linux-mint/</guid>
    </item>
    <item>
      <title>Running Ollama without a GPU</title>
      <link>https://seanmcp.com/articles/running-ollama-without-a-gpu/</link>
      <description>&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; You &lt;em&gt;can&lt;/em&gt; run Ollama on an older device, but the response will be slow
and/or low quality.&lt;/p&gt;
&lt;p&gt;I have successfully run Ollama with a new Macbook M2 and a mid-range gaming PC,
but I wanted to experiment using an older computer. My personal laptop is a 2017
Lenovo Yoga with Ubuntu and no graphics card. Here are some specs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU: Intel i5-7200U CPU @ 2.50GHz&lt;/li&gt;
&lt;li&gt;RAM: 4GB&lt;/li&gt;
&lt;li&gt;Memory: 128GB SSD&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Following the setup instructions for Linux, Ollama installed fine but printed
the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WARNING: No NVIDIA GPU detected. Ollama will run in CPU-only mode.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was foreshadowing for everything to follow.&lt;/p&gt;
&lt;p&gt;I decided to run &lt;code&gt;mistrel&lt;/code&gt; and sent the model a prompt by the terminal. The
response was streaming in at about one character every four seconds, and my
computer was obviously struggling with the task. I held on for around three
minutes but then had to quit when the response was less than on sentence.&lt;/p&gt;
&lt;p&gt;That seemed conclusive enough, but I decided to try with a smaller model. I ran
&lt;code&gt;tinyllama&lt;/code&gt; and was able to stream responses at a normal rate. However, the
quality of the responses was terrible. I don&#39;t have experience with this model
on a more powerful machine, so I can&#39;t blame the model. But the responses were
so bad that I wouldn&#39;t use it for anything on this device.&lt;/p&gt;
&lt;p&gt;These results were disappointing, but the reality is that running LLMs is
resource intensive. So if you want to try running LLMs locally with Ollama, make
sure you have a modern CPU or a dedicated GPU.&lt;/p&gt;
</description>
      <pubDate>Sat, 24 Feb 2024 10:48:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/running-ollama-without-a-gpu/</guid>
    </item>
    <item>
      <title>Use Ollama with the official Python library</title>
      <link>https://seanmcp.com/articles/use-ollama-with-the-official-python-library/</link>
      <description>&lt;p&gt;Ollama is a great way to get started with AI by using open-source and publically
available large-language models locally on your computer. I wrote previously
about
&lt;a href=&quot;https://seanmcp.com/articles/get-started-prompt-engineering-with-local-llms&quot;&gt;how to get started with the experimental OpenAI API&lt;/a&gt;,
but
&lt;a href=&quot;https://github.com/ollama/ollama-python&quot;&gt;Ollama has a dedicated Python library&lt;/a&gt;
that is even simpler.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install the library: &lt;code&gt;pip3 install ollama&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new python file: &lt;code&gt;touch completion.py&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the following code to &lt;code&gt;completion.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ollama

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_completion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ollama&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;chat&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; messages&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;role&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;user&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&#39;content&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; prompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;message&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;content&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

prompt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;What is the chief end of man?&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;get_completion&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mistral&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the file: &lt;code&gt;python3 completion.py&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There is more information available in the
&lt;a href=&quot;https://github.com/ollama/ollama-python?tab=readme-ov-file#api&quot;&gt;library repo on GitHub&lt;/a&gt;,
including examples for streaming responses and a custom client. For even more
documentation on Ollama, check out the
&lt;a href=&quot;https://github.com/ollama/ollama/tree/main/docs&quot;&gt;&lt;code&gt;/docs&lt;/code&gt; directory in the main repo&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Wed, 21 Feb 2024 17:06:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/use-ollama-with-the-official-python-library/</guid>
    </item>
    <item>
      <title>Get started prompt engineering with local LLMs</title>
      <link>https://seanmcp.com/articles/get-started-prompt-engineering-with-local-llms/</link>
      <description>&lt;p&gt;Ollama is an application for running large-language models locally on your
computer. It gives you access to open-source LLMs that you can prompt directly
with the command line or an endpoint.&lt;/p&gt;
&lt;p&gt;To getting started with local LLMs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download and install Ollama: &lt;a href=&quot;https://ollama.com/download&quot;&gt;https://ollama.com/download&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;When prompted, install the &lt;code&gt;ollama&lt;/code&gt; CLI&lt;/li&gt;
&lt;li&gt;Download and run your first LLM: &lt;code&gt;ollama run llama2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Send your first prompt: “What is the chief end of man?”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The response will be printed to the console.&lt;/p&gt;
&lt;p&gt;Using the CLI is nice, but a better option is to create and send prompts with a
scripting language. I&#39;m going to use Python and OpenAI&#39;s chat completion API,
since that a popular combination. For an example with JavaScript,
&lt;a href=&quot;https://github.com/ollama/ollama/blob/main/docs/openai.md#openai-javascript-library&quot;&gt;see this documentation&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new python file: &lt;code&gt;touch completions.py&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the &lt;code&gt;openai&lt;/code&gt; package: &lt;code&gt;pip3 install openai&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set up your OpenAI client:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# completions.py&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; openai &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; OpenAI

client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; OpenAI&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
     base_url&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;http://localhost:11434&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# ll43a looks like llama&lt;/span&gt;
     api_key&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ollama&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Unused but required&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create your first completion:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# This function is not required, but it&#39;s nice to have&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_completion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prompt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; model&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;llama2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; temperature&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
     messages &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;role&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; prompt&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
     response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;chat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;completions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;create&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
         model&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
         messages&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;messages&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
         temperature&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;temperature&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;choices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;content

response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; get_completion&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;What is the chief end of man?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run your script: &lt;code&gt;python3 completions.py&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s all it takes! For a good introduction to prompt writing, I recommend
&lt;a href=&quot;http://DeepLearning.AI&quot;&gt;DeepLearning.AI&lt;/a&gt;’s
&lt;a href=&quot;https://learn.deeplearning.ai/chatgpt-prompt-eng/&quot;&gt;&lt;em&gt;ChatGPT Prompt Engineering for Developers&lt;/em&gt;&lt;/a&gt;
course.&lt;/p&gt;
</description>
      <pubDate>Fri, 16 Feb 2024 18:59:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/get-started-prompt-engineering-with-local-llms/</guid>
    </item>
    <item>
      <title>Python Reference</title>
      <link>https://seanmcp.com/articles/python-reference/</link>
      <description>&lt;p&gt;&lt;table-of-contents&gt;&lt;/table-of-contents&gt;&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;command-line-arguments&quot; tabindex=&quot;-1&quot;&gt;Command-line arguments&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/python-reference/#command-line-arguments&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Command-line arguments”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;argparse&lt;/code&gt; to configure command-line arguments:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; argparse

VERSION &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;

parser &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; argparse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ArgumentParser&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;description&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Describe your CLI&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add_argument&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-v&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--version&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; action&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; version&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;lorem &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;VERSION&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;help&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;print version and exit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add_argument&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nargs&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;?&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; default&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;help&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;number of sentences to generate (default: 1)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

args &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; parser&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parse_args&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.python.org/3/library/argparse.html&quot;&gt;Read about &lt;code&gt;argparse&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;catching-exceptions&quot; tabindex=&quot;-1&quot;&gt;Catching exceptions&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/python-reference/#catching-exceptions&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Catching exceptions”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;try&lt;/code&gt; and &lt;code&gt;except&lt;/code&gt; to catch exceptions:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# Code that might raise an exception&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; bad_condition&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Or throw your own&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; Exception&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Something went wrong&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;An error occurred: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;formatting-strings&quot; tabindex=&quot;-1&quot;&gt;Formatting strings&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/python-reference/#formatting-strings&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Formatting strings”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Use f strings:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;world&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;reading-a-file&quot; tabindex=&quot;-1&quot;&gt;Reading a file&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/python-reference/#reading-a-file&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Reading a file”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;open&lt;/code&gt; to read a file:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;file.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    contents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;read&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;with&lt;/code&gt; ensures the file is closed when the block is exited.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;writing-a-file&quot; tabindex=&quot;-1&quot;&gt;Writing a file&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/python-reference/#writing-a-file&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Writing a file”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;open&lt;/code&gt; to write a file:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;file.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token builtin&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;with&lt;/code&gt; ensures the file is closed when the block is exited.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;requirements-files&quot; tabindex=&quot;-1&quot;&gt;Requirements files&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/python-reference/#requirements-files&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Requirements files”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;To generate a &lt;code&gt;requirements.txt&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pip freeze &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; requirements.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To install dependencies from a &lt;code&gt;requirements.txt&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pip &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; requirements.txt&lt;/code&gt;&lt;/pre&gt;
</description>
      <pubDate>Wed, 07 Feb 2024 24:19:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/python-reference/</guid>
    </item>
    <item>
      <title>Did OpenAI&#39;s Web Browser GPT leak its prompt?</title>
      <link>https://seanmcp.com/articles/openai-web-browser-gpt-prompt-leak/</link>
      <description>&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/web-browser-gpt-prompt-leaking.png&quot; alt=&quot;&amp;quot;&amp;quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I&#39;m not an expert in LLMs or GPTs, but something about the interaction above
feels wrong.&lt;/p&gt;
&lt;p&gt;When prompted with a simple getting started question, OpenAI&#39;s official Web
Browser GPT seems to have leaked some version of its prompt.&lt;/p&gt;
&lt;p&gt;Here is the conversation transcribed:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Me&lt;/strong&gt;: How do I get started?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Web Browser GPT&lt;/strong&gt;: As a &amp;quot;Web Browser&amp;quot; GPT, your role is to assist users by
leveraging web browsing capabilities to find and provide current, specific, or
detailed information that isn&#39;t included in your pre-existing knowledge base.
Here&#39;s how you can get started:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Understanding User Queries&lt;/strong&gt;: Listen to the user&#39;s request carefully.
Your users might ask for information on recent events, details about a
specific topic, or even assistance in research that requires up-to-date or
specialized information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using the Browser Tool&lt;/strong&gt;: Utilize your browser tool to search the
internet. This can be done by issuing search queries based on the user&#39;s
question. You can view search results and select a number of relevant pages
to read in detail.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Selecting Sources&lt;/strong&gt;: Choose a diverse range of sources to ensure a
balanced view. Prioritize trustworthy and reputable sources to maintain
accuracy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extracting and Conveying Information&lt;/strong&gt;: After reading through the
selected pages, synthesize the information in a way that is easy to
understand. Be sure to cite the sources of your information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Staying Within Scope&lt;/strong&gt;: Remember that your primary function is to browse
the web for information. Avoid providing personal opinions or advice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privacy and Ethics&lt;/strong&gt;: Always respect user privacy and avoid accessing or
sharing sensitive, personal, or confidential information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Learning&lt;/strong&gt;: Although you don&#39;t learn from individual
interactions, each query is an opportunity to refine your skills in
searching, selecting, and summarizing information.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If a user asks a question, you should first determine if the answer lies
within your existing knowledge. If it does, provide an answer as usual. If
not, or if the question requires updated information, use your browsing tool
to find and present the answer. Remember, your goal is to assist users by
effectively finding and relaying information from the web.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
      <pubDate>Thu, 18 Jan 2024 18:25:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/openai-web-browser-gpt-prompt-leak/</guid>
    </item>
    <item>
      <title>Migrating from Google Domains to Porkbun was...</title>
      <link>https://seanmcp.com/articles/migrating-from-google-domains-to-porkbun-was-painless/</link>
      <description>&lt;p&gt;&lt;strong&gt;Painless&lt;/strong&gt;. They charged a fee of around $11.00 US to transfer the domain and
then handled the rest seamlessly.&lt;/p&gt;
&lt;p&gt;I was hesitant to make the switch off of Google/Squarespace because I didn’t
know how involved the process would be. I only had two domains on Google, but
there was never a good time to encounter and address downtime issues during a
transfer.&lt;/p&gt;
&lt;p&gt;Thankfully, there weren’t any. I transferred a low-stakes domain first, and from
start to finish it took around 15 minutes. It went so smoothly that I repeated
the process with &lt;a href=&quot;http://seanmcp.com&quot;&gt;seanmcp.com&lt;/a&gt; with the same results.&lt;/p&gt;
&lt;p&gt;Thank you Google Domains for providing a good service and for facilitating an
easy transition. And thank you Porkbun for being a fun alternative. I look
forward to many years of service from a dedicated registrar. &lt;e-moji&gt;🐷&lt;/e-moji&gt;&lt;/p&gt;
</description>
      <pubDate>Thu, 18 Jan 2024 12:41:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/migrating-from-google-domains-to-porkbun-was-painless/</guid>
    </item>
    <item>
      <title>Normalizing data is a good idea</title>
      <link>https://seanmcp.com/articles/normalizing-data-is-a-good-idea/</link>
      <description>&lt;p&gt;On this site I have a few different types of content: articles, notes, gardens,
and now art. There are subtle differences in the data structure for each content
type which come to a head whenever I try to combine them into a single list.&lt;/p&gt;
&lt;p&gt;Previously, I merged all of the content into a single array and then had a bunch
of conditions when rendering for each type:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;articles&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;notes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;gardens&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;art&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;a
          href&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;collection&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;
            item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;collection &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;art&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;slug&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Note #&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;slug&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;time&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pubDate &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tendedDates&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;time&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;article&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works--the complexity needs to live somewhere. But adding new content types
with this setup requires additional conditions that increase the cognitive load
to work with this code.&lt;/p&gt;
&lt;p&gt;An alternative to this is to normalize the data structure so that each content
type can be handled in a similar way. Each type has its own normalization
function, which helps reduce the complexity by addressing one content type at a
time:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;normalizeNotes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;notes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; notes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;note&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; note&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/notes/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;note&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;slug&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Note #&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;note&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;slug&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;pubData&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; note&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pubDate&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once all of the content is normalized, rendering is simpler:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;normalArticles&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;normalNotes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;normalGarden&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;normalArt&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;a href&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;href&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;time&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pubDate&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;time&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;article&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next time I need to add a content type, all I do is write a normalization
function and then slot it in alongside the existing content. That&#39;s scalability!&lt;/p&gt;
&lt;p&gt;This is a personal example, but I think it illustrates the benefits of
normalizing data.&lt;/p&gt;
&lt;p&gt;Normalization functions contain all of the logic to transform data into a
consistent structure. You can focus on one data type at a time, and convert it
into whatever structure makes sense for the current problem.&lt;/p&gt;
&lt;p&gt;Once normalized, you can work with your data in a regular way without worrying
about conditional logic for each type. And down the road, it will be easier to
troubleshoot and develop further when everything is consistent and logic is
isolated.&lt;/p&gt;
&lt;p&gt;Normalization is a good way to make your code more scalable and maintainable
while also reducing cognitive load. So anytime you&#39;re working with multiple
incoming data types, take the time to normalize them first.&lt;/p&gt;
</description>
      <pubDate>Wed, 20 Dec 2023 13:47:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/normalizing-data-is-a-good-idea/</guid>
    </item>
    <item>
      <title>How I&#39;m using AI in November 2023</title>
      <link>https://seanmcp.com/articles/how-im-using-ai-in-november-2023/</link>
      <description>&lt;p&gt;AI products/services that I used regularly (multiple times per week):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt; ⭐: Copilot continues to be a valuable resource when
coding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chat GPT&lt;/strong&gt;: I signed up for the paid version and spent a lot of time working
with custom GPTs. Not sure that the service is worth the price, especially
with rate limits, but I&#39;m viewing it as professional development.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Khanmigo&lt;/strong&gt; 📈: I now work on a AI-product that is powered by Khanmigo daily.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI Products/services that I used occasionally (once per week or less):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dall-E&lt;/strong&gt; 📈: I played around with image generation in the context of custom
GPTs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Warp&lt;/strong&gt;: I probably use this feature once a week to help with a command that
I know exists but can’t remember.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI products/services that I have access to but did not use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bard&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Claude&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cursor&lt;/strong&gt; 📉&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MDN&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Mon, 11 Dec 2023 10:42:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/how-im-using-ai-in-november-2023/</guid>
    </item>
    <item>
      <title>Sli.dev review</title>
      <link>https://seanmcp.com/articles/slidev-review/</link>
      <description>&lt;p&gt;I used &lt;a href=&quot;https://sli.dev/&quot;&gt;sli.dev&lt;/a&gt; to create my slides for my recent talk at
Pittsburgh TechFest 2023. I&#39;ve previously used Google Slides--which is a great
option--but I&#39;ve been interested in finding a good tool for creating slides from
Markdown.&lt;/p&gt;
&lt;p&gt;There were two main motivations for this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I want the content of the slides to be easier to edit and share.&lt;/li&gt;
&lt;li&gt;I want to spend less time fiddling with the design of the slides and more
time on the content.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The main reason to move away from Google Slides is productivity. I find it
incredibly easy to sink tons of prep time into designing slides. It provides a
perfect opportunity to procrastinate when I really need to be working on the
content of the talk.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;pros&quot; tabindex=&quot;-1&quot;&gt;Pros&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/slidev-review/#pros&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Pros”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Design&lt;/strong&gt;: The default designs are high-quality enough that I didn&#39;t feel the
need to customize them to make it look nice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Presenter mode&lt;/strong&gt;: I think this worked better than Google Slides. The ability
to edit content and comments from presenter mode was really useful when
prepping.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Markdown&lt;/strong&gt;: It was really nice to be able to &amp;quot;markup&amp;quot; my slides and comments
with Markdown like bold, italics, and code blocks. That feels like that is
pre-requisite for any dev slides now.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VS Code extension&lt;/strong&gt;: I didn&#39;t use it much, but it was a nice option to have.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;cons&quot; tabindex=&quot;-1&quot;&gt;Cons&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/slidev-review/#cons&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Cons”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Formatting&lt;/strong&gt;: I couldn&#39;t figure out how to get the VS Code formatter working
correctly. If I accidentally hit the format shortcut (which is a reflex of
mine), it broke all of the slides with frontmatter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slide images&lt;/strong&gt;: Slidev has nice options for decorative images with layouts,
but I couldn&#39;t figure out how to position content images correctly. A single
centered image was fine, but if you wanted to have an image beside text then
it was more difficult.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/slidev-review/#conclusion&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Conclusion”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Overall I was happy with Slidev, and I think I will use it again for future
slide decks.&lt;/p&gt;
</description>
      <pubDate>Mon, 27 Nov 2023 13:55:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/slidev-review/</guid>
    </item>
    <item>
      <title>Is it better to have one large file or multiple small files with GPTs?</title>
      <link>https://seanmcp.com/articles/is-it-better-to-have-one-large-file-or-multiple-small-files-with-gpts/</link>
      <description>&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; Using a single file seems to reduce the likelihood of a
knowledge-base loading and improve response times overall.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;: Custom GPTs allow you to upload files that it will reference
when answering questions. In my experience, the response time with these
knowledge-base GPTs is really slow. That lead me to the question:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there a way to improve the response time by altering the number/length of
files in the knowledge base?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I expected that the single large file would result in a faster response time
than many smaller files, because loading an additional file will take longer
than reading the same additional content from an already opened file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Materials and methods&lt;/strong&gt;: I uploaded the maximum number of files with dummy
text to a GPT. One file contained a secret: &lt;code&gt;the secret is: banana bread&lt;/code&gt; (file
6 of 10). I then asked the GPT “what is the secret?” and timed the response with
a stopwatch. In between runs, I removed all of the files and added them back. I
ran it again with single file of approximately equal length that contained the
same secret text.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Results&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Many files (seconds)
&lt;ol&gt;
&lt;li&gt;25.24†&lt;/li&gt;
&lt;li&gt;7.82&lt;/li&gt;
&lt;li&gt;33.81†&lt;/li&gt;
&lt;li&gt;5.96&lt;/li&gt;
&lt;li&gt;23.79†&lt;/li&gt;
&lt;li&gt;7.73&lt;/li&gt;
&lt;li&gt;14.19†&lt;/li&gt;
&lt;li&gt;7.76&lt;/li&gt;
&lt;li&gt;5.92&lt;/li&gt;
&lt;li&gt;8.75&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Single file (seconds)
&lt;ol&gt;
&lt;li&gt;6.92&lt;/li&gt;
&lt;li&gt;6.53&lt;/li&gt;
&lt;li&gt;7.10&lt;/li&gt;
&lt;li&gt;9.62&lt;/li&gt;
&lt;li&gt;11.78&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;† Indicates runs where the GPT indicated knowledge-base loading&lt;/p&gt;
&lt;p&gt;Mean (seconds):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Many files (with loading): 14.97&lt;/li&gt;
&lt;li&gt;Many files (without loading): 7.32&lt;/li&gt;
&lt;li&gt;Single file: 8.39&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Discussion&lt;/strong&gt;: This experiment was pretty hacky! Using a stopwatch was not
ideal, and it was difficult to decide &lt;em&gt;when&lt;/em&gt; to stop with a streaming message.
Response times may have varied significantly due to network connections or
traffic on OpenAI’s servers. We shouldn’t take away any specifics from this
experiment, but we might be able to draw some general insight.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: When the GPT loads from its knowledge base, the response times
were significantly slower. But when it didn’t, or at least didn’t indicated that
it did, the results were similar between multiple files and single files. Based
on this, my hypothesis was wrong. Generally, the response times did not vary
significantly for multiple files &lt;em&gt;vs&lt;/em&gt; a single file.&lt;/p&gt;
&lt;p&gt;However, the data seem to show that using multiple files is more likely to
trigger knowledge-base loading. And since that takes a long time, it is
preferable to use fewer files to improve response time.&lt;/p&gt;
</description>
      <pubDate>Wed, 15 Nov 2023 14:46:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/is-it-better-to-have-one-large-file-or-multiple-small-files-with-gpts/</guid>
    </item>
    <item>
      <title>What is the file limit for GTPs?</title>
      <link>https://seanmcp.com/articles/what-is-the-file-limit-for-gtps/</link>
      <description>&lt;p&gt;&lt;strong&gt;As of 11/15/2023, the limit is 10 files.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Although you wouldn&#39;t know it if you tried to upload more. The UI lets you
upload more than 10 files, but you get an unhelpful &amp;quot;draft failed to save&amp;quot;
message.&lt;/p&gt;
&lt;p&gt;If you inspect the network requests, you&#39;ll see a 🔴 400 to
&lt;code&gt; https://chat.openai.com/backend-api/gizmos&lt;/code&gt; with the following response:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{&amp;quot;detail&amp;quot;:&amp;quot;Cannot upload more than 10 files&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hopefully OpenAI surfaces that error message in the UI soon. In the meantime:
keep your file count to 10 or fewer.&lt;/p&gt;
</description>
      <pubDate>Wed, 15 Nov 2023 13:23:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/what-is-the-file-limit-for-gtps/</guid>
    </item>
    <item>
      <title>How I&#39;m using AI in October 2023</title>
      <link>https://seanmcp.com/articles/how-im-using-ai-in-october-2023/</link>
      <description>&lt;p&gt;This feels like the breakthrough month. I moved to a new project at Khan Academy
working on AI, and I found myself reaching for AI-powered tools more frequently
throughout October. I can see a future where I use some of these daily.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;AI products/services that I used regularly (multiple times per week):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt; ⭐: Copilot continues to be a valuable resource when
coding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chat GPT&lt;/strong&gt; 📈: I don’t know if the quality of the answers changed or I just
had better questions to ask, but I found myself using it regularly this month.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI Products/services that I used occasionally (once per week or less):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cursor&lt;/strong&gt;: A VS-Code-like editor with ChatGPT built in. I used it once while
pairing with a coworker and it was neat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Warp&lt;/strong&gt;: Same as last update, I probably use this feature once a week to help
with a command that I know exists but can’t remember.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI products/services that I have access to but did not use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bard&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Claude&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Khanmigo&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dall-E&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MDN&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Tue, 14 Nov 2023 10:42:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/how-im-using-ai-in-october-2023/</guid>
    </item>
    <item>
      <title>GPTs read text files better than markdown</title>
      <link>https://seanmcp.com/articles/gpts-read-text-files-better-than-markdown/</link>
      <description>&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; Use text files instead of markdown with OpenAI’s custom GPTs&lt;/p&gt;
&lt;p&gt;I conducted an experiment to see if the file type of uploaded content had an
impact on how GPTs could read the information.&lt;/p&gt;
&lt;p&gt;I created two files with the following content:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;secret.md&lt;/code&gt;: &lt;code&gt;the secret is: bananas foster&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;secret.txt&lt;/code&gt;: &lt;code&gt;the secret is: banana split&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then I uploaded one file to a GPT and then asked the question: “What is the
secret?”&lt;/p&gt;
&lt;p&gt;With the markdown file, the GPT consistently had no clue what I was asking for
and refused to or hallucinated an answer. I tried to help by providing some
instructions to look at the uploaded file for the answer. My goal was to provide
a kind of “table of contents” for the GPT to reference.&lt;/p&gt;
&lt;p&gt;Here are some of the iterations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;the secret&amp;quot; is in secret.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;the secret&amp;quot; is in secret.md. Read that file before answering.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;the secret&amp;quot; is in secret.md. Load the contents of that file.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;With other permutations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only success with the markdown file was after selecting “Code interpreter”,
where the GPT wrote (and ran?) a Python script to read and print the contents of
&lt;code&gt;secret.md&lt;/code&gt;. Pretty cool, but definitely not ideal.&lt;/p&gt;
&lt;p&gt;With the text file, it just worked. I uploaded the file and with no instructions
the GPT was able to supply the new secret.&lt;/p&gt;
&lt;p&gt;Based on these results, it is better to use text files with custom GPTs as
opposed to markdown.&lt;/p&gt;
</description>
      <pubDate>Tue, 14 Nov 2023 10:23:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/gpts-read-text-files-better-than-markdown/</guid>
    </item>
    <item>
      <title>Thoughts on Web Speech API</title>
      <link>https://seanmcp.com/articles/thoughts-on-web-speech-api/</link>
      <description>&lt;p&gt;Last week I spent time working with the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis&quot;&gt;Web Speech API&lt;/a&gt;
for a hackathon at Khan Academy. Here are some quick lessons learned from my
experience:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Web Speech is a weird partnership between browser and OS.&lt;/strong&gt; There are
similarities across browsers on a single operating system, and across operating
systems with a single browser. Make sure to test as many browser/OS combinations
as you can.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Voice has a big impact on how text is read.&lt;/strong&gt; I was experimenting a lot with
math expressions, and I found some voices would read with correct math
terminology while others would not. For example, on macOS the default voice
(Samantha) reads &lt;code&gt;3x × 5&lt;/code&gt; as “three times ex five” while Gordon reads it as
“three ex times five”.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The default voice on Ubuntu was really bad.&lt;/strong&gt; Most of the voices on ChromeOS,
macOS, and Windows were fine, but Ubuntu was almost unintelligible. I didn’t
play around with other voice options, but it might be a showstopper if you have
a significant number of Linux users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sometimes &lt;code&gt;speechSynthesis.getVoices()&lt;/code&gt; returns an empty array.&lt;/strong&gt; I couldn’t
find any official documentation about this, but some articles online suggest
that the browser populates that list well after the initial page load. If you
are trying to populate a &lt;code&gt;select&lt;/code&gt; field with voice options, make the request for
voices as late as possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;speechSynthesis.speak()&lt;/code&gt; and &lt;code&gt;speechSynthesis.cancel&lt;/code&gt; are unpredictably
asynchronous.&lt;/strong&gt; I think this goes back to the weird partnership between browser
and OS, but calling &lt;code&gt;speak()&lt;/code&gt; doesn’t happen immediately and &lt;code&gt;cancel()&lt;/code&gt; can
“swallow” subsequent &lt;code&gt;speak()&lt;/code&gt; calls. I needed to use timeouts with a 100ms
delay in a few areas to ensure that the utterance would speak when expected.&lt;/p&gt;
&lt;p&gt;The Web Speech API is neat, but it has a lot of rough edges. It’s unlikely that
a major user-facing feature would use it alone, especially with the rapid
developments in AI text-to-speech. That said, Web Speech provides a solid
foundation to progressively enhance with more power TTS solutions.&lt;/p&gt;
</description>
      <pubDate>Thu, 09 Nov 2023 24:52:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/thoughts-on-web-speech-api/</guid>
    </item>
    <item>
      <title>Declarative code and cognitive load</title>
      <link>https://seanmcp.com/articles/declarative-code-and-cognitive-load/</link>
      <description>&lt;p&gt;If you had asked me ten years ago about my ability to handle cognitive load, I
would have said that I was above average. Today? I would say that I am pretty
bad at holding multiple things in my head at once. Whether that is due to aging,
fatherhood, multiple-bouts of COVID, humility, or any combination of those, I
can’t say.&lt;/p&gt;
&lt;p&gt;What I do know is that I am now very interested in reducing cognitive load so
that I can do my best work.&lt;/p&gt;
&lt;p&gt;In a recent issue of &lt;a href=&quot;https://frontendatscale.com/issues/8/&quot;&gt;Frontend At Scale&lt;/a&gt;,
Maxi Ferreira wrote about how declarative code can reduce cognitive load. Giving
an example service for file uploading with user permissions, Ferreira proposes a
simple list of maps for file extensions and permissions:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This [declarative code solution] doesn&#39;t simplify the relationship between our
services in any way, but it does wonders for reducing cognitive load. We might
still have some complicated logic between our different services, but now we
don&#39;t need to concern ourselves with it. We can now &lt;em&gt;declare&lt;/em&gt; our updated
rules without having to load a bunch of information in our heads.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This feels like a significant insight and is a great solution to the example
problem. You don’t need to know &lt;em&gt;how&lt;/em&gt; the system works (at least, not at first),
but you can quickly understand &lt;em&gt;what&lt;/em&gt; the system does by looking at the
validation rules.&lt;/p&gt;
&lt;p&gt;Now I’m off to brainstorm about how declarative code could reduce some of the
cognitive load in systems I’m working on at Khan Academy. Give the full article
a look and let me know what you think.&lt;/p&gt;
</description>
      <pubDate>Wed, 25 Oct 2023 15:03:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/declarative-code-and-cognitive-load/</guid>
    </item>
    <item>
      <title>How I&#39;m using AI in August &amp; September 2023</title>
      <link>https://seanmcp.com/articles/how-im-using-ai-in-august-september-2023/</link>
      <description>&lt;p&gt;Sorry for two months in one post, but I haven&#39;t been using AI much recently. I
think the trend so far is that AI-powered products that are directly related to
my work are more likely to stick around. All the others come and go more
quickly.&lt;/p&gt;
&lt;p&gt;AI products/services that I used regularly (multiple times per week):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt; ⭐: Copilot continues to be a valuable resource when
coding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI Products/services that I used occasionally (once per week or less):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Warp&lt;/strong&gt; 📈: I have used Warp&#39;s AI-powered command suggestion occasionally
over the past two months. It&#39;s helpful when I&#39;m looking for a git command or
something similar but can&#39;t quite remember the flags or syntax.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI products/services that I have access to but did not use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bard&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bing&lt;/strong&gt; 📉&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Khanmigo&lt;/strong&gt; 📉&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dall-E&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MDN&lt;/strong&gt; 📉&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Tue, 03 Oct 2023 21:22:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/how-im-using-ai-in-august-september-2023/</guid>
    </item>
    <item>
      <title>See what object properties are accessed in JavaScript</title>
      <link>https://seanmcp.com/articles/see-what-object-properties-are-accessed-in-javascript/</link>
      <description>&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/see-what-object-properties-are-accessed.png&quot; alt=&quot;A magnifying glass that is inspecting a JavaScript object&quot;&gt;&lt;/p&gt;
&lt;p&gt;At work I was mocking an object to be passed to a React context provider. I knew
the type for the object, but I wanted to learn what properties were being
accessed on the object from this point in the component tree.&lt;/p&gt;
&lt;p&gt;Thankfully, JavaScript has a native way to &amp;quot;watch&amp;quot; an object and respond
whenever any of its properties are accessed or reassigned:
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy&quot;&gt;a Proxy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First start with the object that you want to watch:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;createdAt&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then pass your object to the &lt;code&gt;Proxy&lt;/code&gt; constructor along with a handler object
that determines what you want to do you when a property is get or set:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; userProxy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; property&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Getting &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;property&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; on &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;target&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;property&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; property&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Setting &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;property&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; on &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;target&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; to &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;value&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    target&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;property&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can use &lt;code&gt;userProxy&lt;/code&gt; as if it were the original &lt;code&gt;user&lt;/code&gt; object. I passed
the proxy into the context provider and then watched then checked the console to
see what properties for that object were accessed.&lt;/p&gt;
&lt;p&gt;Nice and easy! Let me know if you have any other use cases for a proxy in
JavaScript.&lt;/p&gt;
</description>
      <pubDate>Thu, 28 Sep 2023 10:30:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/see-what-object-properties-are-accessed-in-javascript/</guid>
    </item>
    <item>
      <title>Remove duplicates from an array in JavaScript</title>
      <link>https://seanmcp.com/articles/remove-duplicates-from-an-array-in-javascript/</link>
      <description>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/seanmcp/image/upload/v1692892991/remove-duplicates-in-array_ptvagw.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Removing duplicates, sometimes called de-duplicating or de-duping, is a common
task in programming. There are many ways for removing duplicates from an array
in JavaScript, and here I am going to share two scenarios and strategies.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;array-of-primitive-values&quot; tabindex=&quot;-1&quot;&gt;Array of primitive values&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-duplicates-from-an-array-in-javascript/#array-of-primitive-values&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Array of primitive values”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In JavaScript,
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#primitive_values&quot;&gt;primitive values&lt;/a&gt;
are the simplest form of data like strings and numbers. Let&#39;s say you have an
array of strings:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; original &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can de-duplicate this array by using it to create a set, a special object
that only stores unique values. We&#39;ll pass it to the &lt;code&gt;Set&lt;/code&gt; constructor, and then
compare the two by looking at how many items they contain:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; original &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; set &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;original&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;original&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; vs &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; set&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &quot;4 vs 3&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final step is to convert this new set back into an array. We can do this
with the &lt;code&gt;Array.from&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; original &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; set &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;original&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deDuped &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;set&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;original&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;b&quot;]&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deDuped&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that strategy, we could write a one-liner or create a helper function for
reuse later:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; original &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deDuped &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;original&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;deDupePrimitiveArray&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;deDupePrimitiveArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;original&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think this is a nice and modern solution to remove duplicates from simple
arrays, but &lt;em&gt;it will not work&lt;/em&gt; when you have an array of objects. For that,
we&#39;ll need a different strategy.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;array-of-objects&quot; tabindex=&quot;-1&quot;&gt;Array of objects&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-duplicates-from-an-array-in-javascript/#array-of-objects&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Array of objects”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In JavaScript, object-like values like objects and arrays need a different
strategy for removing duplicates. Let&#39;s say you have an array of objects with a
unique &lt;code&gt;id&lt;/code&gt; property:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; original &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can use this &lt;code&gt;id&lt;/code&gt; to keep track of which objects we have already seen. There
are multiple options to do this, but let&#39;s stick with sets since we used that in
the last example. We&#39;ll create a new set to keep track of ids that we&#39;ve already
seen:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; original &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; seen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we filter the original array by checking if the current object&#39;s id is in
the set. If it is, then we know that this object is a duplicate and can be
filtered out:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; original &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; seen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; deDuped &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; original&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [{ id: &quot;a&quot; }, { id: &quot;b&quot; }, { id: &quot;c&quot; }]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can&#39;t write a one-liner for this, but we can create a helper function. In
addition to the array, we&#39;ll need to accept a function that maps an item in the
array to the unique property that we&#39;ll use for comparison:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; original &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;deDupeObjectArray&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mapper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; seen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; key &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mapper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;deDupeObjectArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;original&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [{ id: &quot;a&quot; }, { id: &quot;b&quot; }, { id: &quot;c&quot; }]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have a mapper function, we can combine this with the previous
strategy to create a single function that can de-dupe both primitive and object
arrays.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;bringing-it-all-together&quot; tabindex=&quot;-1&quot;&gt;Bringing it all together&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-duplicates-from-an-array-in-javascript/#bringing-it-all-together&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Bringing it all together”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;To create a function that will remove duplicates from an array of primitive or
object-like values, we can take the solution for object arrays and modify it
slightly with a default mapper function:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;deDupe&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;mapper&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; seen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; key &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mapper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    seen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can use this function to remove duplicates from primitive or object
arrays:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;deDupe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;deDupe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [{ id: &quot;a&quot; }, { id: &quot;b&quot; }, { id: &quot;c&quot; }]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see all of the examples above in this REPL:
&lt;a href=&quot;https://replit.com/@SeanMcP/removing-duplicates-in-arrays#index.ts&quot;&gt;https://replit.com/@SeanMcP/removing-duplicates-in-arrays#index.ts&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Fri, 25 Aug 2023 10:38:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/remove-duplicates-from-an-array-in-javascript/</guid>
    </item>
    <item>
      <title>How I&#39;m using AI in July 2023</title>
      <link>https://seanmcp.com/articles/how-im-using-ai-in-july-2023/</link>
      <description>&lt;p&gt;AI products/services that I used regularly (multiple times per week):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt; ⭐: Copilot continues to be a valuable resource when
coding. I was working on a script while offline, and I missed seeing it&#39;s
suggestions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI Products/services that I used occasionally (once per week or less):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bing Images&lt;/strong&gt; &amp;amp; &lt;strong&gt;ChatGPT&lt;/strong&gt;: I used these for a small project (creating a
fantasy RPG to play with my kids), but it didn&#39;t end up going anywhere.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Khanmigo&lt;/strong&gt;: Khan Academy has their own AI offering that I have access to
through work. It&#39;s neat, but I&#39;m not convinced how useful it is for the
average user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MDN&lt;/strong&gt;: MDN launched a new AI-powered search feature that I tried a few
times. The results weren&#39;t great: nothing for information that should have
been easy to find, and some incorrect answers. But I can see potential in
something like that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI products/services that I have access to but did not use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bard&lt;/strong&gt; 📉&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bing&lt;/strong&gt; 📉&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dall-E&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Warp&lt;/strong&gt; 📉&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Tue, 08 Aug 2023 10:47:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/how-im-using-ai-in-july-2023/</guid>
    </item>
    <item>
      <title>Timeboxing types</title>
      <link>https://seanmcp.com/articles/timeboxing-types/</link>
      <description>&lt;p&gt;Two things that I currently believe:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There is a lot of value in statically typed code&lt;/li&gt;
&lt;li&gt;Writing types is a potential time sink with diminishing returns&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I don&#39;t feel like I need to justify the first belief. The trend in the front-end
industry towards TypeScript illustrates that there is a growing consensus that
types are a net positive.&lt;/p&gt;
&lt;p&gt;That second belief probably needs more of a defense. I think there is a general
maximum value for any given type, and the additional value derived from writing
a type decrease over timer. Plotted on a chart, I think it looks something like
this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/value-of-writing-types.png&quot; alt=&quot;A chart showing the value of writing types decreasing over time&quot;&gt;&lt;/p&gt;
&lt;p&gt;Despite this knowledge, my brain is still tempted to spend significant amounts
of time writing the &amp;quot;perfect&amp;quot; type. I find myself giving away a lot of
additional time while deriving little to no additional value.
&lt;a href=&quot;https://v5.chriskrycho.com/journal/is-typescript-good/&quot;&gt;Chris Krycho, an engineer at LinkedIn, puts it this way&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Type systems very often do mash a puzzle-solving button in our brains.
Figuring out how to get the types &lt;em&gt;just right&lt;/em&gt; for a given design can lead an
unwary developer (reader: I mean myself) into an hours-long maze. Getting out
of one of those mazes with a good solution feels incredibly satisfying. But it
is not always &lt;em&gt;worth&lt;/em&gt; it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The puzzle metaphor rings true for me. As with other puzzles, we want to spend
the time to &amp;quot;solve&amp;quot; them. And as the types grow more complex, so too does the
amount of time required for the &amp;quot;solution&amp;quot;. I don&#39;t know if I can say
exponentially, but that doesn&#39;t feel far off.&lt;/p&gt;
&lt;p&gt;The reality is that a basic type written quickly will probably get you 90+% of
the benefits of the &amp;quot;perfect&amp;quot; type. Chris continues:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A simpler type might be a little less precise, might catch a couple fewer
errors, might make the system mildly less robust at runtime, might make it
possible for there to be runtime bugs the system could in principle have ruled
out entirely by clever use of the type system… and be 100% worth those
tradeoffs given the context.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think the solution to marry beliefs 1 and 2 is to &lt;strong&gt;timebox the amount of time
that you spend writing any given type&lt;/strong&gt;. Give yourself 5 minutes to write the
best type that you can, and then move on.&lt;/p&gt;
&lt;p&gt;If you can write the perfect type--&amp;quot;solve&amp;quot; that puzzle--then great! But if not,
that&#39;s okay too. You surely have enough value in the type to justify the time
you spent writing it.&lt;/p&gt;
&lt;p&gt;This timeboxed writing should be in combination with an effort to master the
type system you are using. As you grow in your understanding of the system, the
quality of the types that you can write within your timebox will increase.&lt;/p&gt;
&lt;p&gt;Is 5 minutes enough time? That depends. If you are new to the type system, you
might need a little more time to write a valuable type. Or if you are dealing
with a mission-critical type, it might be worthwhile to invest more time. If you
are authoring a library that will be shared widely with the organization or
world, then a more-perfect type will probably be worth the time (if only to save
yourself future support work).&lt;/p&gt;
&lt;p&gt;But for the average developer with some experience writing types, I think 5
minutes is a good starting point.&lt;/p&gt;
&lt;p&gt;Try it out, and
&lt;a href=&quot;mailto:sean@seanmcp.com?subject=I%20tried%20timeboxing%20types&quot;&gt;let me know what you think&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Wed, 02 Aug 2023 10:14:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/timeboxing-types/</guid>
    </item>
    <item>
      <title>CSS columns are neat</title>
      <link>https://seanmcp.com/articles/css-columns-are-neat/</link>
      <description>&lt;p&gt;I was looking for a solution to dynamically create two columns in a UI when I
came across the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/columns&quot;&gt;&lt;code&gt;columns&lt;/code&gt; CSS property&lt;/a&gt;.
With a single property, you can tell the browser to split content evenly between
&lt;em&gt;n&lt;/em&gt; number of columns:&lt;/p&gt;
&lt;div class=&quot;example stack()&quot; style=&quot;columns: 2&quot;&gt;
&lt;p&gt;&lt;strong&gt;Two columns&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ornare augue
placerat, malesuada nulla volutpat, pharetra arcu. Aenean consectetur diam in
justo interdum, eu pharetra purus congue.&lt;/p&gt;
&lt;p&gt;Sed cursus porta lorem, non posuere ex sagittis nec. Nam pulvinar rutrum
condimentum. Proin sodales neque eget eros vulputate, vel hendrerit sem mollis.
Sed quis faucibus quam.&lt;/p&gt;
&lt;p&gt;Etiam at enim id quam posuere feugiat non posuere est. Donec dictum lacus
posuere augue congue, ac tincidunt velit dignissim. Quisque hendrerit eros vel
erat ornare porta.&lt;/p&gt;
&lt;p&gt;Nunc viverra enim dui, sit amet dapibus lacus mollis vel. Donec vitae lorem
sagittis, vulputate mauris a, posuere est. Nam nulla urna, laoreet in massa id,
finibus tincidunt risus.&lt;/p&gt;
&lt;p&gt;Aliquam quam massa, varius ac dolor ac, pharetra hendrerit eros. Suspendisse at
facilisis leo, vel posuere dui. In hac habitasse platea dictumst. Proin congue
euismod metus quis dictum.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;example stack()&quot; style=&quot;columns: 3&quot;&gt;
&lt;p&gt;&lt;strong&gt;Three columns&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ornare augue
placerat, malesuada nulla volutpat, pharetra arcu. Aenean consectetur diam in
justo interdum, eu pharetra purus congue.&lt;/p&gt;
&lt;p&gt;Sed cursus porta lorem, non posuere ex sagittis nec. Nam pulvinar rutrum
condimentum. Proin sodales neque eget eros vulputate, vel hendrerit sem mollis.
Sed quis faucibus quam.&lt;/p&gt;
&lt;p&gt;Etiam at enim id quam posuere feugiat non posuere est. Donec dictum lacus
posuere augue congue, ac tincidunt velit dignissim. Quisque hendrerit eros vel
erat ornare porta.&lt;/p&gt;
&lt;p&gt;Nunc viverra enim dui, sit amet dapibus lacus mollis vel. Donec vitae lorem
sagittis, vulputate mauris a, posuere est. Nam nulla urna, laoreet in massa id,
finibus tincidunt risus.&lt;/p&gt;
&lt;p&gt;Aliquam quam massa, varius ac dolor ac, pharetra hendrerit eros. Suspendisse at
facilisis leo, vel posuere dui. In hac habitasse platea dictumst. Proin congue
euismod metus quis dictum.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;You can also set a certain width for the columns:&lt;/p&gt;
&lt;div class=&quot;example stack()&quot; style=&quot;columns: 10ch&quot;&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;10ch&lt;/code&gt; width&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas ornare augue
placerat, malesuada nulla volutpat, pharetra arcu. Aenean consectetur diam in
justo interdum, eu pharetra purus congue.&lt;/p&gt;
&lt;p&gt;Sed cursus porta lorem, non posuere ex sagittis nec. Nam pulvinar rutrum
condimentum. Proin sodales neque eget eros vulputate, vel hendrerit sem mollis.
Sed quis faucibus quam.&lt;/p&gt;
&lt;p&gt;Etiam at enim id quam posuere feugiat non posuere est. Donec dictum lacus
posuere augue congue, ac tincidunt velit dignissim. Quisque hendrerit eros vel
erat ornare porta.&lt;/p&gt;
&lt;p&gt;Nunc viverra enim dui, sit amet dapibus lacus mollis vel. Donec vitae lorem
sagittis, vulputate mauris a, posuere est. Nam nulla urna, laoreet in massa id,
finibus tincidunt risus.&lt;/p&gt;
&lt;p&gt;Aliquam quam massa, varius ac dolor ac, pharetra hendrerit eros. Suspendisse at
facilisis leo, vel posuere dui. In hac habitasse platea dictumst. Proin congue
euismod metus quis dictum.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I don&#39;t come across many use cases for this magazine-style layout, but it&#39;s nice
to know that CSS has solution for it.&lt;/p&gt;
</description>
      <pubDate>Tue, 01 Aug 2023 11:18:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/css-columns-are-neat/</guid>
    </item>
    <item>
      <title>Quality requires iteration</title>
      <link>https://seanmcp.com/articles/quality-requires-iteration/</link>
      <description>&lt;p&gt;You&#39;re not going to get it right the first time. You might not even get it right
the second time. But if you iterate enough, you&#39;re going to find a good
solution.&lt;/p&gt;
&lt;p&gt;Too often I catch myself overanalyzing the first pass at a problem. I spend too
much time &lt;em&gt;thinking&lt;/em&gt; about how the whole system needs to work, or all of the
edge cases that need to be addressed, and trying to plan the Perfect™ solution.&lt;/p&gt;
&lt;p&gt;But it is never the case that plan A is the final solution. So why spend so much
time agonizing over the first attempt?&lt;/p&gt;
&lt;p&gt;Think about the problem that you need to solve, sure. Consider the edge cases
that come to mind, definitely. Then move quickly on to building something.&lt;/p&gt;
&lt;p&gt;Write a function once to figure out how it needs to work, and then write it
again now that you know more.&lt;/p&gt;
&lt;p&gt;Throw a bunch of messy components in a single file while you figure out what the
UI requires and how you can compose them. Then refactor and move things into
their own files (with individual stories and tests).&lt;/p&gt;
&lt;p&gt;If you have time, iterate again... and maybe again. Each pass should get faster
and more direct, because your knowledge of the problem is increasing the the
picture of the solution is growing more clear.&lt;/p&gt;
&lt;p&gt;Plan to make several attempts at the solution. Plan to delete what you&#39;ve
written. Plan for several rounds of code review. Plan to plan less up front and
more as you go.&lt;/p&gt;
&lt;p&gt;Quality in programming requires iterations. So lean into it.&lt;/p&gt;
</description>
      <pubDate>Tue, 01 Aug 2023 10:57:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/quality-requires-iteration/</guid>
    </item>
    <item>
      <title>A workable emoji picker on Ubuntu</title>
      <link>https://seanmcp.com/articles/a-workable-emoji-picker-on-ubuntu/</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://github.com/SeanMcP?tab=repositories&amp;amp;q=emoji&amp;amp;sort=stargazers&quot;&gt;I like to use emojis&lt;/a&gt;
and have missed them since moving to Linux/Ubuntu. They render fine, but there
isn’t a good way to input emojis into a field like on macOS and Windows.&lt;/p&gt;
&lt;p&gt;Technically there is a native GNOME emoji picker, but it only works with
“&lt;a href=&quot;https://itsfoss.com/ubuntu-emojis/&quot;&gt;supported GTK 3 applications&lt;/a&gt;” and I don’t
use
&lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_GTK_applications&quot;&gt;any of those regularly&lt;/a&gt;.
I tried installing a few third-party options, but none of them worked well.&lt;/p&gt;
&lt;p&gt;I thought that I was resigned to not using emojis often on Linux, when one day I
discovered suggested emojis in the
&lt;a href=&quot;https://help.ubuntu.com/stable/ubuntu-help/shell-introduction.html.he#activities&quot;&gt;Activities overview’s&lt;/a&gt;
search results.&lt;/p&gt;
&lt;p&gt;Here are the steps that work for me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Press the super key (formerly Windows)&lt;/li&gt;
&lt;li&gt;Type the name of the emoji: &lt;em&gt;e.g.&lt;/em&gt; turtle&lt;/li&gt;
&lt;li&gt;Select the emoji result from the Characters application to copy to clipboard&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;In addition to your mouse, you can use &lt;kbd&gt;tab&lt;/kbd&gt; and the up/down arrow
keys to navigate the options 🙌&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Paste the emoji in your application&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This process is not perfect: there are some emojis that are hard to find by
name, and the lack of browsing makes discoverability a challenge. However, it’s
definitely good enough for me for now.&lt;/p&gt;
&lt;p&gt;It would be nice if all applications could use the GNOME emoji picker, but I’m
too new here to know if that is even possible. A man can dream.&lt;/p&gt;
</description>
      <pubDate>Wed, 05 Jul 2023 11:25:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/a-workable-emoji-picker-on-ubuntu/</guid>
    </item>
    <item>
      <title>Writing Prompts for Programmers</title>
      <link>https://seanmcp.com/articles/writing-prompts-for-programmers/</link>
      <description>&lt;blockquote&gt;
&lt;p&gt;The most effective way I know to improve your writing is to do freewriting
exercises regularly. --
&lt;a href=&quot;https://www.research.ucsb.edu/sites/default/files/RD/docs/FREEWRITING-by-Peter-Elbow.pdf&quot;&gt;Peter Elbow&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;prompts&quot; tabindex=&quot;-1&quot;&gt;Prompts&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/writing-prompts-for-programmers/#prompts&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Prompts”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;random-prompt&gt;
&lt;ul&gt;
&lt;li&gt;What is a tool that you have been using lately?&lt;/li&gt;
&lt;li&gt;What tool would you miss the most if it were to disappear?&lt;/li&gt;
&lt;li&gt;What is the first thing that you look to do when setting up a new computer?&lt;/li&gt;
&lt;li&gt;What is a process that has been painful recently? How might you fix it?&lt;/li&gt;
&lt;li&gt;What is a product that you think should exist?&lt;/li&gt;
&lt;li&gt;What is a programming pattern that you have been appreciating lately?&lt;/li&gt;
&lt;li&gt;What is a programming pattern that you have been avoiding lately?&lt;/li&gt;
&lt;li&gt;Is there any value in bikeshedding? Why or why not?&lt;/li&gt;
&lt;li&gt;How would you compare two solutions to a problem?&lt;/li&gt;
&lt;li&gt;What are three strategies for reversing a list of strings?&lt;/li&gt;
&lt;/ul&gt;
&lt;/random-prompt&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;how-to-use-these-prompts&quot; tabindex=&quot;-1&quot;&gt;How to use these prompts&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/writing-prompts-for-programmers/#how-to-use-these-prompts&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “How to use these prompts”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;These prompts were curated for freewriting, an exercise to help you get started
writing. To start, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pick a prompt that piques your interest&lt;/li&gt;
&lt;li&gt;Grab a pen and paper or open a text editor&lt;/li&gt;
&lt;li&gt;Set a timer for 5, 10, or 15 minutes&lt;/li&gt;
&lt;li&gt;Write until the timer goes off&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you are done, it&#39;s up to you: stop or continue, discard or publish. The
goal was to write and strengthen those muscles, and you&#39;ve succeeded!&lt;/p&gt;
</description>
      <pubDate>Tue, 04 Jul 2023 14:51:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/writing-prompts-for-programmers/</guid>
    </item>
    <item>
      <title>Reviewing &quot;Go By Example&quot;</title>
      <link>https://seanmcp.com/articles/reviewing-go-by-example/</link>
      <description>&lt;p&gt;I started &lt;a href=&quot;https://gobyexample.com/&quot;&gt;Go By Example&lt;/a&gt; in April with the goal of
learning the language for work. &lt;a href=&quot;https://khanacademy.org&quot;&gt;Khan Academy&lt;/a&gt; (and my
old company &lt;a href=&quot;https://niche.com&quot;&gt;Niche&lt;/a&gt;) use Go for their back-end services. And
while I am focused on the front end, knowledge of the Go language is valuable
for my work.&lt;/p&gt;
&lt;p&gt;It took me 80 days from start to finish to complete the 79 examples. After a few
starts and stops in the beginning, I settled into a routine of starting each day
(barring Sunday) by working through an example. This felt like a good pace to
learn the syntax and patterns slowly so that it sticks. And I think that it has,
for the most part!&lt;/p&gt;
&lt;p&gt;Overall, I enjoyed the exercises, and I would recommend Go By Example to anyone
who is interested in learning the Go language. The examples were focused and
clear, and the progression of concepts was logical. After completing the course,
I feel confident reading and writing Go, and feel like I could contribute to an
existing project.&lt;/p&gt;
&lt;p&gt;One criticism of the course is that it does little to explain how Go projects
work beyond simple scripts. I don’t have clear understanding of “packages” in Go
which made it difficult to explore the language with side projects. There was an
example on how to make a simple HTTP server but no details on how to deploy one.&lt;/p&gt;
&lt;p&gt;To be fair, that wasn’t the point of the course. But if you’re looking for a
more holistic introduction to Go, you might need to supplement Go By Example
with something else.&lt;/p&gt;
&lt;p&gt;So I’m looking for an additional resource to fill in some of those knowledge
gaps. If you have any recommendations,
&lt;a href=&quot;mailto:sean@seanmcp.com?subject=Go%20Resources&quot;&gt;please let me know&lt;/a&gt;. Otherwise,
I’ll write again when I have found something that works well.&lt;/p&gt;
</description>
      <pubDate>Tue, 04 Jul 2023 10:51:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/reviewing-go-by-example/</guid>
    </item>
    <item>
      <title>How I&#39;m Using AI in June 2023</title>
      <link>https://seanmcp.com/articles/how-im-using-ai-in-june-2023/</link>
      <description>&lt;p&gt;AI products/services that I used regularly (multiple times per week):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt; ⭐: Copilot continues to be a valuable resource when
coding.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI Products/services that I used occasionally (once per week or less):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bard&lt;/strong&gt; 📉: Although a rising star last month, I found that the quality of
its answers seemed to decrease over the past month. That could be due to the
types of questions I was asking (primarily Go coding questions) or changes
under the hood.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bing&lt;/strong&gt; 📉: I use Edge as my daily browser and will occasionally send it a
question, but it doesn’t play a big part in my workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Warp&lt;/strong&gt; 📉: Handy to look up a common command without leaving the terminal,
but that isn’t something that I need to do regularly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI products/services that I have access to but did not use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bing Images&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt; 📉&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dall-E&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Fri, 23 Jun 2023 10:57:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/how-im-using-ai-in-june-2023/</guid>
    </item>
    <item>
      <title>A quick comparison of JavaScript and Go executables</title>
      <link>https://seanmcp.com/articles/quick-comparison-of-javascript-and-go-executables/</link>
      <description>&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;: Bun and Deno, JavaScript runtimes, provide a native way to
convert your JavaScript code into a single executable file.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bun: &lt;code&gt;bun build --compile my-script.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Deno: &lt;code&gt;deno compile my-script.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To create these executables, Bun and Deno need to include their entire JS
runtime in the executable file. That means all of Apple’s JavaScriptCore for Bun
and Google’s V8 for Deno. But once that is compiles, the executables should work
in any environment that those runtimes support.&lt;/p&gt;
&lt;p&gt;I wanted to compare these new JavaScript options and Go to see if JS is a
legitimate option for creating cross-environment executables.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;: I created a project for a simple command-line utility for reading
&lt;code&gt;package.json&lt;/code&gt; files from the terminal:
&lt;a href=&quot;https://github.com/seanmcp/rpj&quot;&gt;github.com/seanmcp/rpj&lt;/a&gt;. Then I implemented the
utility in all three environments: Bun, Deno, and Go. I have Bash scripts to
create the executables and then compare the results by two metrics: file size
and execution time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The numbers&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;File size&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bun: 97733752 bytes or 97.7 megabytes&lt;/li&gt;
&lt;li&gt;Deno: 109968928 bytes or 110.0 megabytes&lt;/li&gt;
&lt;li&gt;Go: 2607443 bytes or 2.6 megabytes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Go created the smallest executable (by a wide margin). I ran into issues with
the Deno executable being rejected by GitHub for being too large, and Bun isn’t
far behind.&lt;/p&gt;
&lt;p&gt;Execution time&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bun: 0:00.04 real, 0.02 user, 0.01 sys&lt;/li&gt;
&lt;li&gt;Deno: 0:00.04 real, 0.02 user, 0.01 sys&lt;/li&gt;
&lt;li&gt;Go: 0:00.00 real, 0.00 user, 0.00 sys&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The execution time was not a major factor in my example, and my hypothesis is
that most of the difference is due to the startup cost of the JavaScript
runtime. We would need more tests to determine how big the difference in
execution time between these options.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: Based on these results, Go is still the superior option for
executables based on file size and execution time. However, Bun and Deno
provided a great authoring experience for developers who are familiar with the
JavaScript ecosystem. And the ability to use pre-existing tools and processes
when creating executables might make Bun or Deno the best option for you and
your team.&lt;/p&gt;
&lt;p&gt;Personally, I’m excited to see how this feature of JavaScript runtimes develops
over time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Afterward&lt;/strong&gt;: Node.js does have an experimental feature to create executables,
but at the time of writing
&lt;a href=&quot;https://nodejs.org/docs/latest-v20.x/api/single-executable-applications.html&quot;&gt;the steps were too involved&lt;/a&gt;.
For open-source options for creating Node executables, checkout
&lt;a href=&quot;https://github.com/nexe/nexe&quot;&gt;nexe&lt;/a&gt; and &lt;a href=&quot;https://github.com/vercel/pkg&quot;&gt;pkg&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Mon, 05 Jun 2023 11:34:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/quick-comparison-of-javascript-and-go-executables/</guid>
    </item>
    <item>
      <title>Compairing Objects, Maps, and WeakMaps for lookup tables in JavaScript</title>
      <link>https://seanmcp.com/articles/compairing-objects-maps-and-weakmaps-for-lookup-tables-in-javascript/</link>
      <description>&lt;p&gt;I use lookup tables/dictionaries/hashmaps/maps a lot when I’m coding. That’s a
data structure that stores key and value pairs that are easily retrievable. Here
is an example table for storing and looking up element names by their symbol
written in Python that uses a dictionary:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;periodic_table&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;H&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hydrogen&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;periodic_table&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;H&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Hydrogen&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In JavaScript, we have three tools for this pattern—Objects, Maps, and
WeakMaps—each with strengths and weaknesses.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;objects&quot; tabindex=&quot;-1&quot;&gt;Objects&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/compairing-objects-maps-and-weakmaps-for-lookup-tables-in-javascript/#objects&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Objects”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Objects are the standard data type for dictionaries. They are so flexible that
they are, in a way, the base prototype for all values in JavaScript. Entries are
added and retrieved with dot or bracket notation, and then removed with the
&lt;code&gt;delete&lt;/code&gt; keyword:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Declare&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; periodicTable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Set&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;H&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hydrogen&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// dot notation&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;He&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Helium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// bracket notation&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Get&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;Hydrogen&quot;&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;He&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;Helium&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Delete&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Li &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Lithium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Li&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Object are not strictly iterable, but you can use &lt;code&gt;for...in&lt;/code&gt; to access its keys
or the global Object’s methods to get an iterable array: &lt;code&gt;Object.keys()&lt;/code&gt;,
&lt;code&gt;Object.values()&lt;/code&gt;, and &lt;code&gt;Object.entries()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; periodicTable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; periodicTable&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// H Hydrogen&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// He Helium&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;periodicTable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [&quot;H&quot;, &quot;He&quot;]&lt;/span&gt;
Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;periodicTable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [&quot;Hydrogen&quot;, &quot;Helium&quot;]&lt;/span&gt;
Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;periodicTable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [[&quot;H&quot;, &quot;Hydrogen&quot;], [&quot;He&quot;, &quot;Helium&quot;]]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Objects will work as a data structure for every problem you encounter. So in
some ways, it is the best of the three options for lookup tables. Some
weaknesses of Objects are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prototype properties can conflict with keys in table&lt;/li&gt;
&lt;li&gt;Key types limited to strings, numbers, and symbols&lt;/li&gt;
&lt;li&gt;No guaranteed entry order&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;maps&quot; tabindex=&quot;-1&quot;&gt;Maps&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/compairing-objects-maps-and-weakmaps-for-lookup-tables-in-javascript/#maps&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Maps”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Map&lt;/code&gt; object was added to JavaScript in ES2015 and provides a dedicated
native solution for lookup tables. Entries are added, retrieved, and removed
with dedicated methods:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Declare&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; periodicTable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Set&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;H&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hydrogen&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;He&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Helium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Get&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;H&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;Hydrogen&quot;&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;He&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;Helium&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Delete&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Li&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Lithium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Li&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Maps are iterable so you can access all of the entries with a &lt;code&gt;for...of&lt;/code&gt; loop
(similar to Arrays). They also have a &lt;code&gt;Map.forEach()&lt;/code&gt; method which provides the
same data but (curiously) in the reverse order:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; entry &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; periodicTable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&quot;H&quot;, &quot;Hydrogen&quot;]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&quot;He&quot;, &quot;Helium&quot;]&lt;/span&gt;

periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// H Hydrogen&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// He Helium&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Maps also have &lt;code&gt;Map.keys()&lt;/code&gt; and &lt;code&gt;Map.values()&lt;/code&gt; methods that return iterators for
keys and values, but the use cases for those might be rare. More common are the
&lt;code&gt;Map.has()&lt;/code&gt; method which returns a boolean of whether a key exists, and
&lt;code&gt;Map.size&lt;/code&gt; getter which returns the number of key/value pairs.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Li&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// false&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some other features that would take more time to illustrate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preserved entry order&lt;/li&gt;
&lt;li&gt;More performant than objects for frequent additions and subtractions&lt;/li&gt;
&lt;li&gt;Support any data structure for keys, including objects and functions (this
makes them a good choice for implementing memoization)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is for these methods/features that Maps really shine as data types of lookup
tables. The main weaknesses for Maps are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Not serializable&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;weakmaps&quot; tabindex=&quot;-1&quot;&gt;WeakMaps&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/compairing-objects-maps-and-weakmaps-for-lookup-tables-in-javascript/#weakmaps&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “WeakMaps”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;WeakMaps&lt;/code&gt; were added to JavaScript along with &lt;code&gt;Maps&lt;/code&gt; in ES2015. A noticeable
difference between the two is that keys in &lt;code&gt;WeakMaps&lt;/code&gt; must be objects. Entries
are added, retrieved, and deleted with dedicated methods:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Declare&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; periodicTable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WeakMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Set&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;H&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;H&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hydrogen&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Get&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;Hydrogen&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Delete&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; He &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;He&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;He&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Helium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;He&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: There is nothing special about the &lt;code&gt;{ symbol: &amp;quot;&amp;quot; }&lt;/code&gt; syntax here. I’m
just creating an object for each key that makes sense for the periodic-table
example. You could use any object or object-like value for the key: &lt;code&gt;{}&lt;/code&gt;, &lt;code&gt;[]&lt;/code&gt;,
&lt;code&gt;() =&amp;gt; {}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Unlike Maps, WeakMaps are not iterable and there is no way to access its size.
The only method provided is &lt;code&gt;WeakMap.has()&lt;/code&gt; to receive a boolean of whether that
key exists or not:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;periodicTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;He&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of these differences are due to a shift in focus. WeakMaps are special in
that they weakly reference the objects used as keys. This weak reference means
that JavaScript can garbage collect those objects sooner, which will improve the
memory performance of your application.&lt;/p&gt;
&lt;p&gt;If you have a long-living lookup table, this memory-performance feature may be
the perfect solution. Some weaknesses of WeakMaps are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Limited key types&lt;/li&gt;
&lt;li&gt;No iteration or access to keys/values list&lt;/li&gt;
&lt;li&gt;Not serializable&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;try-it-out&quot; tabindex=&quot;-1&quot;&gt;Try it out&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/compairing-objects-maps-and-weakmaps-for-lookup-tables-in-javascript/#try-it-out&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Try it out”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I created a REPL that includes all of the code examples above for you to
explore:
&lt;a href=&quot;https://replit.com/@SeanMcP/JavaScript-lookup-tables#index.js&quot;&gt;replit.com/@SeanMcP/JavaScript-lookup-tables&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/compairing-objects-maps-and-weakmaps-for-lookup-tables-in-javascript/#conclusion&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Conclusion”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;What is the best tool for implementing lookup tables in JavaScript? The answer
will vary depending on your specific use case, but here are some general
recommendations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Map&lt;/code&gt; is (probably) the best&lt;/strong&gt;: Between flexible key types, preserved
order, easy iteration, and helpful methods, Maps have all of the features
that you need for 90% of lookup tables that you will write in your code.
Learning the syntax is a worthwhile investment over basic Objects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Otherwise use an &lt;code&gt;Object&lt;/code&gt;&lt;/strong&gt;: That said, you could still implement every
lookup table with an Object. One scenario where objects shine is for inline
lookups:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getElementName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token constant&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hydrogen&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;He&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Helium&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;symbol&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;WeakMap&lt;/code&gt; for performance&lt;/strong&gt;: If you are working in a situation where memory
performance is important, then WeakMap’s weakly referenced keys will be
helpful. There are other programming problems where WeakMaps shine, but we’re
looking specifically for lookup tables.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now that you know the different tools that JavaScript offers for
dictionaries/hash maps/maps/lookup tables, you can choose the best solution in
your context.&lt;/p&gt;
</description>
      <pubDate>Mon, 22 May 2023 11:24:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/compairing-objects-maps-and-weakmaps-for-lookup-tables-in-javascript/</guid>
    </item>
    <item>
      <title>Web-browser Accessibility Tools</title>
      <link>https://seanmcp.com/articles/web-browser-accessibility-tools/</link>
      <description>&lt;p&gt;Khan Academy celebrates Global Accessibility Awareness Day with a whole week of
activities. Yesterday on GAAD proper, we were encouraged to set aside our normal
work and pick up some accessibility tasks from the backlog or do some
a11y-focused professional development.&lt;/p&gt;
&lt;p&gt;They also hosted four accessibility lightning talks, and I was happy to give one
on a11y tools built into modern web browser. The talk consisted of quick tours
through Chrome, Edge, Firefox, and Safari that highlighted some of their
accessibility features.&lt;/p&gt;
&lt;p&gt;I enjoy preparing presentations about the browser dev tools because it is a
perfect excuse for me to learn more about the tools that I have at my disposal.
Some of the cool new features that I learned about were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vision-deficiency emulators&lt;/strong&gt; in Chrome (Rendering tab) and Firefox
(Accessibility panel)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interactive accessibility trees&lt;/strong&gt; in Firefox (Accessibility panel) and
Chrome (experimental - Inspect panel)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Targeted accessibility audits&lt;/strong&gt; in Firefox (Accessibility panel) and Safari
(Audit panel)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visualized tab order&lt;/strong&gt; in Firefox (Accessibility panel)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic Axe scans&lt;/strong&gt; in Edge (Issues tab)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The recording is private, but my outline for the talk is available at
&lt;a href=&quot;https://seanmcp.com/talks/browser-a11y-tools&quot;&gt;/talks/browser-a11y-tools/&lt;/a&gt;. I might re-record the
talk for &lt;a href=&quot;https://youtube.com/@seanmcp&quot;&gt;YouTube&lt;/a&gt;, so subscribe if you’re so
inclined.&lt;/p&gt;
&lt;p&gt;Overall, its encouraging to see all of the major browsers putting time and
effort into creating tools to help developers built accessible applications. Now
we all just need to use them!&lt;/p&gt;
</description>
      <pubDate>Fri, 19 May 2023 11:07:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/web-browser-accessibility-tools/</guid>
    </item>
    <item>
      <title>Linux Update in 2023</title>
      <link>https://seanmcp.com/articles/linux-update-in-2023/</link>
      <description>&lt;p&gt;Last year I experimented with using a Raspberry Pi as a home development
environment. The device was ultimately too low powered, but my interest was
piqued. Linux has improved a lot since my last experiments with it in the early
2010s.&lt;/p&gt;
&lt;p&gt;Encouraged by that experience and
&lt;a href=&quot;https://definingterms.com/&quot;&gt;a coworker who uses Linux&lt;/a&gt; at work and home or
development, I decided to try again with a more powerful device. I considered
buying a new laptop—&lt;a href=&quot;https://www.pine64.org/pinebook-pro/&quot;&gt;Pinebook&lt;/a&gt; and
&lt;a href=&quot;https://system76.com/laptops-ultraportables&quot;&gt;System76&lt;/a&gt; look promising—but I
opted instead for a Lenovo Yoga from 2017 that we had lying around. It has an
Intel i5, 128GB SSD, and 4GB of RAM which felt sufficient. Plus, it feels good
to give new life to an old device.&lt;/p&gt;
&lt;p&gt;After some internal debate, I ended up installing Ubuntu. There are probably
distros that would have been better for an older device with simpler specs, but
bog standard should be good enough for me. I didn’t have any issues with drivers
this time (🙌), and the only feature that I lost was the fingerprint reader.
Overall, the experience of installing Linux on the laptop was great.&lt;/p&gt;
&lt;p&gt;Outside of work, I’ve been using this Linux laptop almost exclusively for the
past month. It runs well, the battery life is decent (Power Mode helps a lot),
and Ubuntu has been a great development environment. I work mostly in the
JavaScript world, and the computer is able to handle some resource-intensive
Node.js processes. I’ve also been learning Go, and all of that runs without the
fan.&lt;/p&gt;
&lt;p&gt;I’ve installed Microsoft Edge for browsing and VS Code for editing, but outside
of that I’m trying to keep things lean. I know that 128GB will fill up fast, so
I’m trying to limit installs to only the essentials. To date, that hasn’t been a
limiting factor: turns out your don’t need much to write web apps and Go
scripts!&lt;/p&gt;
&lt;p&gt;In summary, I’m happy with my current set up. The experimenting with Linux in
2022 helped prepare me to use it as my daily driver in 2023.&lt;/p&gt;
</description>
      <pubDate>Tue, 16 May 2023 12:49:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/linux-update-in-2023/</guid>
    </item>
    <item>
      <title>How I&#39;m using AI in May 2023</title>
      <link>https://seanmcp.com/articles/how-im-using-ai-in-may-2023/</link>
      <description>&lt;p&gt;As of May 2023, I use the following AI-powered products on at least a weekly
basis:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub Copilot ⭐&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writing code&lt;/strong&gt;: typically this is autocomplete to the end of the line, but
occasionally it generates small blocks of code. Rarely I use it to generate a
Regex for a particular pattern, saving me a search, copy, and paste from
StackOverflow.&lt;/li&gt;
&lt;li&gt;ChatGPT&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversations&lt;/strong&gt;: the best for prompt engineering, it runs with a persona
that you give it. I’ve found rubber-duck sessions with a “helpful coworker who
asks insightful questions” to be really helpful.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generating structured code&lt;/strong&gt;: creates a list of ten objects that match a
given structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Document drafting&lt;/strong&gt;: I needed to write a charter for a church building
committee and had no clue where to start. A few prompts to ChatGPT, and I had
an outline and draft to follow.&lt;/li&gt;
&lt;li&gt;Bing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internet searches&lt;/strong&gt;: if I have a question that would typically require more
than one search, then I’ll ask Bing. It does a good job of answering &lt;em&gt;with&lt;/em&gt;
citations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Summarizing content&lt;/strong&gt;: given a URL, Bing does a good job of summarizing
content from a web page. You can even ask for comprehension questions if
you’re reading to learn.&lt;/li&gt;
&lt;li&gt;Bard 📈&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coding questions&lt;/strong&gt;: Bard gives the right balance of length and depth for
questions I have about programming. It usually includes helpful code snippets.&lt;/li&gt;
&lt;li&gt;Warp&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Command suggestions&lt;/strong&gt;: saves a lot of time searching for those common
commands that you can never seem to remember, &lt;em&gt;e.g.&lt;/em&gt; “how to undo the last
commit?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As of May 2023, I have access to but no interest in the following products:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Midjourney/Dall·E/Bing Images&lt;/strong&gt;: I’ve seen some of the things they generate,
and while some of it is cool none of it feels useful to me.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion&lt;/strong&gt;: I don’t need an AI to write content for me.&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Sat, 13 May 2023 12:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/how-im-using-ai-in-may-2023/</guid>
    </item>
    <item>
      <title>Declaring variables in Go</title>
      <link>https://seanmcp.com/articles/declaring-variables-in-go/</link>
      <description>&lt;p&gt;There are three ways to declare variables in Go: &lt;code&gt;var&lt;/code&gt;, &lt;code&gt;:=&lt;/code&gt;, and &lt;code&gt;const&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;var&lt;/code&gt; keyword is the standard method for declaring a variable. It can be
used anywhere in your program, with a value or without:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; s1 &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; s2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;World&quot;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; s3 &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;
	s3 &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;!&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Variable declarations without a value require a type (&lt;code&gt;s3&lt;/code&gt; above), but types are
otherwise optional.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Declare a variable with with &lt;code&gt;var&lt;/code&gt; when you need a variable at the top-level
of your program or want to initialize it with no value.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The short-declaration operator, &lt;code&gt;:=&lt;/code&gt;, works like the &lt;code&gt;var&lt;/code&gt; keyword for declaring
variables with three differences: a) it can only be used within the scope of a
function, b) it cannot initialize an empty variable, and c) it does not accept a
type. Of the &lt;code&gt;var&lt;/code&gt; examples above, only one could be replaced with a &lt;code&gt;:=&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// s1 := &quot;Hello&quot; // Outside of function scope&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	s2 &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;World&quot;&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// s3 := // No empty variables&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These may sounds like significant limitations, but most of your program will be
written inside a function’s scope and rarely do variables need to be declared
without a value. So the benefit of using &lt;code&gt;:=&lt;/code&gt; comes from letting Go infer the
type of your variable so that you can focus on the code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Declare a variable with &lt;code&gt;:=&lt;/code&gt; when you are working within a function with
initial values.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;const&lt;/code&gt; keyword tells the compiler that the variable is a constant -- it
will not be changed or reassigned. Like &lt;code&gt;var&lt;/code&gt; it can be used anywhere in your
program but can only be used with some types: &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;float64&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, and
&lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; PI &lt;span class=&quot;token builtin&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3.14159&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you try to use &lt;code&gt;const&lt;/code&gt; with other types like a &lt;code&gt;slice&lt;/code&gt;, then you will get a
compiler error:
&lt;code&gt;(value of type []string) is not constant compiler(InvalidConstInit)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Declare a variable with &lt;code&gt;const&lt;/code&gt; when you know that it will not change
throughout your program.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I am new to learning and writing in Go, but in practice I almost exclusively use
the declaration operator, &lt;code&gt;:=&lt;/code&gt;, for declaring variables. But it’s useful to know
the reasons when and why you should reach for &lt;code&gt;var&lt;/code&gt; or &lt;code&gt;const&lt;/code&gt;.&lt;/p&gt;
</description>
      <pubDate>Fri, 12 May 2023 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/declaring-variables-in-go/</guid>
    </item>
    <item>
      <title>What is nullish in JavaScript?</title>
      <link>https://seanmcp.com/articles/what-is-nullish-in-javascript/</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing&quot;&gt;Nullish-coalescing operator&lt;/a&gt;
(&lt;code&gt;??&lt;/code&gt; or double question mark) is a handy tool that returns the right-hand
operand when the left-hand is nullish. In JavaScript, nullish is defined as
&lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I enjoy using the nullish coalescing operator in my code, especially combined
with optional chaining:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; response&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;user&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Anonymous&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will return the user&#39;s name if &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; exist on the
&lt;code&gt;response&lt;/code&gt; variable, or fallback to &amp;quot;Anonymous&amp;quot; if not.&lt;/p&gt;
&lt;p&gt;However, I tend to get nullish confused with falsy in JavaScript. And while
there is some overlap, it is important to know and remember the difference
between the two.&lt;/p&gt;
&lt;p&gt;Common &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Falsy&quot;&gt;falsy values&lt;/a&gt;
are &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;, and &lt;code&gt;NaN&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Nullish values are a subset of that at just &lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/falsy-nullish-js.png&quot; alt=&quot;Nullish values as a subset of falsy values&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you try to use the nullish-coalescing operator with a falsy value, it will
return the left-hand operand:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;fallback&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To state it one more time, nullish in JavaScript is &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;. All
other values, even if they are falsy, are excluded. So reach for nullish
coalescing only when dealing with &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;. Otherwise use logical
OR (&lt;code&gt;||&lt;/code&gt;) or a ternary operator (&lt;code&gt;? :&lt;/code&gt;).&lt;/p&gt;
</description>
      <pubDate>Thu, 11 May 2023 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/what-is-nullish-in-javascript/</guid>
    </item>
    <item>
      <title>QA questions for everyone to ask</title>
      <link>https://seanmcp.com/articles/qa-questions-for-everyone-to-ask/</link>
      <description>&lt;p&gt;My former colleague Michael Scotto recently
&lt;a href=&quot;https://thequalityindex.com/three-types-of-questions-qa-must-ask-5b907a7102fe&quot;&gt;wrote about quality assurance and asking questions&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Many use phrases like “QA Engineer” and “Tester” interchangeably. It’s
convenient to do so, and generally innocuous — but &lt;strong&gt;this is narrow
thinking.&lt;/strong&gt; To think of Quality Assurance as “testing” is reductive; it puts a
governor on the value-add of your QA team.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Testing is a skill, not a job.&lt;/strong&gt; Instead, think of QA as the art of asking
unasked questions. Testing is only one way to do this. It’s a coincidence that
“QA” could also represent “Question Asker”, but it’s a meaningful coincidence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He lists three types of questions to ask:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Verification: Does X do Y?&lt;/li&gt;
&lt;li&gt;Discovery: What happens if…?&lt;/li&gt;
&lt;li&gt;Criticism: Does this make sense?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I really like this breakdown, and he includes more examples in the article. It
illustrates the reality that assuring quality transcends any functional team:
everyone is responsible, because everyone can and should be asking these types
of questions.&lt;/p&gt;
&lt;p&gt;As an engineer, I should to be asking verification questions throughout the
development process. I’ll probably codify those questions by writing unit and
end-to-end tests. Answering these questions should be the baseline before
handing the work off to another team member.&lt;/p&gt;
&lt;p&gt;But I should also be asking discovery questions to surface edge cases that need
to be addressed. Some of those are apparent when writing the code, “Oo, we
aren’t handling this state case”, but other times it’s based on user
interaction. I need to play around a bit and look for those pitfalls.&lt;/p&gt;
&lt;p&gt;And all the while I should ask critical questions: does this implementation make
sense? Will it meet the needs of our users? What about folks on low-powered
devices or those with disabilities? If the answer to those questions are
unsatisfactory, then I might need to work out a different solution.&lt;/p&gt;
&lt;p&gt;Personally, I find asking verification and criticism questions easy; it’s
discovery questions that I often overlook. This article was a good framework for
thinking about quality assurance and reminder that I need to play my part in the
process as well.&lt;/p&gt;
</description>
      <pubDate>Wed, 10 May 2023 18:04:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/qa-questions-for-everyone-to-ask/</guid>
    </item>
    <item>
      <title>Learning Go</title>
      <link>https://seanmcp.com/articles/learning-go/</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://niche.com&quot;&gt;Niche&lt;/a&gt; and &lt;a href=&quot;https://khanacademy.org&quot;&gt;Khan Academy&lt;/a&gt; use Go
for their backend services, so I&#39;ve been &amp;quot;reading&amp;quot; Go since 2019. But as I
progress in my career, I&#39;m realizing that it would be useful to understand Go at
a deeper level, and even write some Go code when the need arises.&lt;/p&gt;
&lt;p&gt;For the past few weeks I&#39;ve been going through
&lt;a href=&quot;https://gobyexample.com&quot;&gt;&lt;em&gt;Go by Example&lt;/em&gt;&lt;/a&gt;, a &amp;quot;hands-on introduction to Go using
annotated example programs&amp;quot;, and logging my progress here:
&lt;a href=&quot;https://github.com/seanmcp/go-by-example&quot;&gt;seanmcp/go-by-example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So far, I am enjoying the experience. &lt;em&gt;Go by Example&lt;/em&gt; is well designed: the
examples are clear and the concepts build upon each other well. And the
development environment setup for Go is straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;install Go,&lt;/li&gt;
&lt;li&gt;write &lt;code&gt;.go&lt;/code&gt; files in your editor of choice, and&lt;/li&gt;
&lt;li&gt;run programs from the command line.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&#39;ve been using VS Code with the official Go extension, and it&#39;s been great --
even on an older laptop.&lt;/p&gt;
&lt;p&gt;My favorite features so far:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The built-in &lt;strong&gt;formatter&lt;/strong&gt;: it&#39;s nice to not have to think about how your code
should be formatted.&lt;/li&gt;
&lt;li&gt;Generating &lt;strong&gt;executables&lt;/strong&gt;: I&#39;ve played around with Deno&#39;s compiler for this,
but Go&#39;s feels more mature.&lt;/li&gt;
&lt;li&gt;Simple &lt;strong&gt;syntax&lt;/strong&gt;: you don&#39;t need to remember a lot of syntax to write Go
code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My not-so-favorites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Conventions are &lt;strong&gt;too terse&lt;/strong&gt;: you can name things whatever you want, but
reading through examples with 1-3 letter variables gets old. &lt;code&gt;timer.C&lt;/code&gt; is not
explicit.&lt;/li&gt;
&lt;li&gt;The name &lt;strong&gt;Go&lt;/strong&gt;: it&#39;s too common a word for a programming language, which
makes searching online for challenging. Using &amp;quot;golang&amp;quot; tends to work, but even
the title of this article might confuse people.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The negatives aside, I&#39;m looking forward to continuing this journey. If you have
any recommendations or resources, please let me know!&lt;/p&gt;
</description>
      <pubDate>Tue, 09 May 2023 10:44:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/learning-go/</guid>
    </item>
    <item>
      <title>Set up Decap CMS</title>
      <link>https://seanmcp.com/articles/set-up-decap-cms/</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://decapcms.org/&quot;&gt;Decap CMS&lt;/a&gt; is the official
&lt;a href=&quot;https://www.netlify.com/blog/netlify-cms-to-become-decap-cms/&quot;&gt;successor to Netlify CMS&lt;/a&gt;
and works well with the old tooling. Here are the steps to get up and running
with Decap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step-by-step&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add a new page route for &lt;code&gt;/admin&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;For me, this was &lt;code&gt;src/pages/admin.astro&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Copy and paste
&lt;a href=&quot;https://decapcms.org/docs/add-to-your-site/#app-file-structure&quot;&gt;the markup from the documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Add &lt;a href=&quot;https://decapcms.org/docs/configuration-options&quot;&gt;a &lt;code&gt;config.yml&lt;/code&gt; file&lt;/a&gt; to
your public directory&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;netlify-cms-proxy-server&lt;/code&gt; alongside your dev server:&lt;pre&gt;&lt;code&gt;npx netlify-cms-proxy-server
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Access the content manager at &lt;code&gt;localhost:XXXX/admin/&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Issues&lt;/strong&gt;: Decap CMS &lt;em&gt;still&lt;/em&gt; hasn&#39;t fixed
&lt;a href=&quot;https://github.com/netlify/netlify-cms/issues/5092&quot;&gt;the jumping cursor issue when inserting within a textarea&lt;/a&gt;.
It makes writing content incredibly frustrating. Thankfully, there is a fix that
requires some additional CSS (of all things):&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- admin.html --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;
  &lt;span class=&quot;token selector&quot;&gt;[data-slate-editor]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* See https://github.com/netlify/netlify-cms/issues/5092 */&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;-webkit-user-modify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; read-write &lt;span class=&quot;token important&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With those style loaded, the issue is resolved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaways&lt;/strong&gt;: Decap CMS is easy to set up and works well with all of Netlify
CMS&#39; old tooling. It&#39;s nice to hear that the project will live on with new
maintainers, but it remains to be seen how invested they will be in development
like fixing old bugs.&lt;/p&gt;
</description>
      <pubDate>Wed, 19 Apr 2023 01:02:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/set-up-decap-cms/</guid>
    </item>
    <item>
      <title>Zed is a rocket-powered skateboard</title>
      <link>https://seanmcp.com/articles/zed-is-a-rocket-powered-skateboard/</link>
      <description>&lt;p&gt;Zed is a new Rust-powered editor by the creator of Atom that focuses on speed
but lacks a lot of features.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My experience&lt;/strong&gt;: I downloaded Zed after hearing
&lt;a href=&quot;https://changelog.com/podcast/531&quot;&gt;the creator talk about it on the Changelog podcast&lt;/a&gt;.
And my first impression was that it just feels fast. Opening the application,
navigating projects, and editing files are all zippy. The integrated terminal
does the job without fanfare.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The numbers&lt;/strong&gt;: Zed compares itself favorably to Sublime Text, VS Code, and
CLion
&lt;a href=&quot;https://zed.dev/#engineered-for-performance&quot;&gt;in three metrics on its homepage&lt;/a&gt;,
but I found Sublime to have a significantly smaller install size:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sublime Text – 126MB&lt;/li&gt;
&lt;li&gt;Zed – 312MB&lt;/li&gt;
&lt;li&gt;VS Code – 526MB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Trade-offs&lt;/strong&gt;: Zed is missing a lot of features that I expect from a modern
editor.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The editor is missing autocomplete, block moving shortcuts, and does silly
things like matching quotation marks in comments.&lt;/li&gt;
&lt;li&gt;The search is missing find and replace, filtering by path or filetype, and
collapsing/removing results.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a result, my rate of development was noticeably slower in Zed than in VS
Code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway&lt;/strong&gt;: Zed is a fast editor in the same vein as Sublime Text and is a
good option for a lightweight second editor. But for modern front-end
development, Zed lacks the features to be your daily driver.&lt;/p&gt;
&lt;p&gt;There are a number of interesting collaboration features that I haven’t tested.
I didn’t want to ask a coworker to download Zed when I knew the editor was
lacking.&lt;/p&gt;
&lt;p&gt;Zed has a solid foundation that may enable it to outpace other editors in the
future – but it’s not there yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read more&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://zed.dev/&quot;&gt;https://zed.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://changelog.com/podcast/531&quot;&gt;https://changelog.com/podcast/531&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Sat, 01 Apr 2023 10:32:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/zed-is-a-rocket-powered-skateboard/</guid>
    </item>
    <item>
      <title>Fix failed Fastify deploy on Render</title>
      <link>https://seanmcp.com/articles/fix-failed-fastify-deploy-on-render/</link>
      <description>&lt;p&gt;To get a boilerplate Fastify app to deploy on &lt;a href=&quot;http://Render.com&quot;&gt;Render.com&lt;/a&gt;, you need to read to
listen on PORT environment variable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;: When trying to deploy a basic Fastify app to &lt;a href=&quot;http://Render.com&quot;&gt;Render.com&lt;/a&gt;, I
received a generic failure method: &lt;code&gt;Deploy failed for COMMIT_HASH&lt;/code&gt;. The log
indicated that the server started correctly, and there was no information
indicating why the deploy failed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The fix&lt;/strong&gt;: I couldn’t find docs for running Fastify on
&lt;a href=&quot;http://Render.com&quot;&gt;Render.com&lt;/a&gt;, but there are example repos for other languages
and libraries. The Render example for Express
&lt;a href=&quot;https://github.com/render-examples/express-hello-world/blob/main/app.js#L3&quot;&gt;included a reference&lt;/a&gt;
to &lt;code&gt;process.env.PORT&lt;/code&gt;. By adding that to my Fastify app, I was able to
successfully deploy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Copy and paste&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; server &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fastify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; port &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’re using TypeScript, you will have to convert the environment variable to
a number:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// TypeScript&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; port &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Read more&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.fastify.io/docs/latest/&quot;&gt;https://www.fastify.io/docs/latest/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://render.com/docs&quot;&gt;https://render.com/docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/render-examples/express-hello-world/blob/main/app.js#L3&quot;&gt;https://github.com/render-examples/express-hello-world/blob/main/app.js#L3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Tue, 28 Mar 2023 21:01:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-failed-fastify-deploy-on-render/</guid>
    </item>
    <item>
      <title>Find and replace with Regex groups</title>
      <link>https://seanmcp.com/articles/find-and-replace-with-regex-groups/</link>
      <description>&lt;p&gt;Create Regex groups with parentheses for powerful find/replace patterns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;: I have a markdown file with a lot of shorthand links to GitHub PRs,
&lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;user/repo#1&lt;/code&gt;, that I wanted to be replaced with full URLs:
&lt;code&gt;https://github.com/user/repo/issues/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These steps are for VS Code, but you can do a Regex find/replace in any
environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step by step:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the search panel in VS Code&lt;/li&gt;
&lt;li&gt;Turn on Regex searches with the &lt;code&gt;.*&lt;/code&gt; toggle&lt;/li&gt;
&lt;li&gt;Search with the following Regex pattern: &lt;code&gt;([&#92;w-]+)/(.+)#(&#92;d+)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;This looks for any text that matches the pattern of:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;([&#92;w-]+)&lt;/code&gt; a word containing one more alphanumeric or hyphen characters,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt; a forward slash,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(.+)&lt;/code&gt; one or more of any character,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#&lt;/code&gt; a pound sign, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(&#92;d+)&lt;/code&gt; one or more digits&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It creates three groups (identified by the parentheses)&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Replace the matched text with the following pattern:
&lt;code&gt;https://github.com/$1/$2/issues/$3&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Try it out:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://regexr.com/7a3kb&quot;&gt;https://regexr.com/7a3kb&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tradeoffs:&lt;/strong&gt; The regex pattern above will only match for alphanumeric GitHub
usernames with optional hyphens. I don’t know the official pattern used to
validate usernames, so your data might include some that don’t match.&lt;/p&gt;
</description>
      <pubDate>Tue, 14 Mar 2023 10:50:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/find-and-replace-with-regex-groups/</guid>
    </item>
    <item>
      <title>Fix SVG CSS animation issue in Safari</title>
      <link>https://seanmcp.com/articles/fix-svg-css-animation-issue-in-safari/</link>
      <description>&lt;p&gt;Safari 16 has trouble with CSS animations on SVG child elements, but you can
resolve them by using a combined &lt;code&gt;transform&lt;/code&gt; property.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; You have an SVG that needs separate animations for its &lt;code&gt;path&lt;/code&gt; and
&lt;code&gt;rect&lt;/code&gt; elements. Applying a single transform to the elements works, but
combining multiple transforms results in nondeterministic animation bugs:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; worksInSafari&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; brokenInSafari&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0deg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20deg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; You can fix this by combining your transformations into multiple
functions on a single &lt;code&gt;transform&lt;/code&gt; property:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; fixedInSafari&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0deg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;20deg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Try it out:&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;css,result&quot; data-slug-hash=&quot;dyqVxvY&quot; data-user=&quot;SeanMcP&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/SeanMcP/pen/dyqVxvY&quot;&gt;
  Safari CSS animation SVG bug&lt;/a&gt; by Sean McPherson (&lt;a href=&quot;https://codepen.io/SeanMcP&quot;&gt;@SeanMcP&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Individual properties for CSS transforms are nice, but they can
cause issues with SVG animations in Safari. The safer option seems to be
sticking with a single &lt;code&gt;transform&lt;/code&gt; property for now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read more:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/a/72022385/8486161&quot;&gt;https://stackoverflow.com/a/72022385/8486161&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/transform&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/transform&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Fri, 10 Mar 2023 10:45:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-svg-css-animation-issue-in-safari/</guid>
    </item>
    <item>
      <title>Listen for class change in JavaScript</title>
      <link>https://seanmcp.com/articles/listen-for-class-change-in-javascript/</link>
      <description>&lt;p&gt;There isn’t an event for class list changes, but you can write a function that
listens for class changes on an element with the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver&quot;&gt;MutationObserver API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Copy &amp;amp; paste&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;onClassChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;node&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lastClassString &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mutationObserver &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MutationObserver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mutationList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; item &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; mutationList&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;attributeName &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;class&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; classString &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;classString &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; lastClassString&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token function&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mutationObserver&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          lastClassString &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; classString&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  mutationObserver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;node&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; mutationObserver&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Step by step&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The function accepts two parameters: a reference to a DOM node to watch and
the callback to execute when the class has changed.&lt;/li&gt;
&lt;li&gt;Within the function, we store a reference to the class list as a string that
we will use for comparison later.&lt;/li&gt;
&lt;li&gt;Create a new &lt;code&gt;MutationObserver&lt;/code&gt; instance with a callback that listens for
class changes.
&lt;ol&gt;
&lt;li&gt;Inside that callback, we loop through the mutation list and look for any
changes to the &lt;code&gt;class&lt;/code&gt; attribute.&lt;/li&gt;
&lt;li&gt;If we find one, then we compare the current class list as a string to the
reference declared above.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;This comparison is necessary to prevent false class change positives, &lt;em&gt;e.g&lt;/em&gt;
adding the same class twice.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;If the class strings do not match, invoke the callback and update the
class string reference.&lt;/li&gt;
&lt;li&gt;Break out of the loop if we have detected a change.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Observe the passed node with the new mutation observer instance and configure
it to fire on attribute changes.&lt;/li&gt;
&lt;li&gt;Return the mutation observer for later clean up&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Try it out:&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;js,result&quot; data-slug-hash=&quot;VwGzxQb&quot; data-user=&quot;SeanMcP&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/SeanMcP/pen/VwGzxQb&quot;&gt;
  Function to listen for class change&lt;/a&gt; by Sean McPherson (&lt;a href=&quot;https://codepen.io/SeanMcP&quot;&gt;@SeanMcP&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; It would be nice if there was a standard method for listening to
class changes, but it is nice to know that you can write your own with a
&lt;code&gt;MutationObserver&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read more:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.seanmcp.com/articles/event-listener-for-class-change/&quot;&gt;https://www.seanmcp.com/articles/event-listener-for-class-change/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Thu, 09 Mar 2023 11:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/listen-for-class-change-in-javascript/</guid>
    </item>
    <item>
      <title>Create Axios-style articles with CSS</title>
      <link>https://seanmcp.com/articles/create-axios-style-articles-with-css/</link>
      <description>&lt;p&gt;You can style heading elements to look like the axioms in Axios articles with
CSS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step by step:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Start with the following HTML markup for this example:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Paragraph 1&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Why it matters&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Paragraph 2 should be inline with the heading&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Turning over to CSS, add
&lt;a href=&quot;https://every-layout.dev/layouts/stack/&quot;&gt;stack styles&lt;/a&gt; the container
element:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article * + *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin-block-start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1.5rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This positions all of our block elements within an &lt;code&gt;article&lt;/code&gt; with a
consistent gap.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move the &lt;code&gt;h2&lt;/code&gt; and following &lt;code&gt;p&lt;/code&gt; elements onto the same line:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article h2,
article h2 + p&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This positions those element correctly, but creates a problem. The block
start margin of the &lt;code&gt;h2&lt;/code&gt; element isn’t collapsing with the block end margin
of the first paragraph.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Remove block end margins for everything within our article:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article *&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin-block-end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a colon using a pseudo-element:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;article h2::after&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With those styles in place, we have a semantic and accessible Axios article.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Try it out:&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;yLxXoxN&quot; data-user=&quot;SeanMcP&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/SeanMcP/pen/yLxXoxN&quot;&gt;
  Axios-style articles with h2 headings&lt;/a&gt; by Sean McPherson (&lt;a href=&quot;https://codepen.io/SeanMcP&quot;&gt;@SeanMcP&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; This solution is better than Axios’ markup because it uses the
heading hierarchy. They use &lt;code&gt;strong&lt;/code&gt; elements which aren’t navigable by
screenreaders.&lt;/p&gt;
</description>
      <pubDate>Mon, 06 Mar 2023 18:52:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/create-axios-style-articles-with-css/</guid>
    </item>
    <item>
      <title>CSS :empty pseudo class</title>
      <link>https://seanmcp.com/articles/css-empty-pseudo-class/</link>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:empty&lt;/code&gt; allows you to apply styles to an element when it has no child nodes&lt;/li&gt;
&lt;li&gt;This is useful for hiding empty elements to keep visual grids consistent&lt;/li&gt;
&lt;li&gt;It is supported in all major browsers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When building a user interface, it is common to have a container element that
conditionally contains content. A simple example is an element that displays
error information when a form field is invalid. To accomplish this, you have two
options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Always render the container in the DOM and conditionally add children (&lt;em&gt;e.g.&lt;/em&gt;
text, other nodes)&lt;/li&gt;
&lt;li&gt;Conditionally render the container when needed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are use cases for both approaches. When working with vanilla JavaScript, I
typically reach for the former. If I were building the interface with a
front-end library, then I use the later.&lt;/p&gt;
&lt;p&gt;A problem that arises with option 1 is spacing in between elements. If you are
using flex box or grid with a &lt;code&gt;gap&lt;/code&gt; the empty element will be included in the
layout and will result in a double space between visible elements.&lt;/p&gt;
&lt;p class=&quot;codepen&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;KKxaQmo&quot; data-user=&quot;SeanMcP&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot;&gt;
  &lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/SeanMcP/pen/KKxaQmo&quot;&gt;
  Removing extra flex/grid spacing with :empty&lt;/a&gt; by Sean McPherson (&lt;a href=&quot;https://codepen.io/SeanMcP&quot;&gt;@SeanMcP&lt;/a&gt;)
  on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;The solution is to use the :empty pseudo class to select the empty element and
hide it with display: none. Once the element is removed from the flex/grid, the
gap between elements are consistent.&lt;/p&gt;
&lt;p&gt;It is worth noting that the double spacing is not an issue with patterns like
Every Layout’s stack, which uses the browser&#39;s collapsing margins. But if you
are using flexbox or grid, then the problem will eventually arise.&lt;/p&gt;
</description>
      <pubDate>Thu, 02 Mar 2023 11:08:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/css-empty-pseudo-class/</guid>
    </item>
    <item>
      <title>Fix trailing whitespace in Astro components</title>
      <link>https://seanmcp.com/articles/fix-trailing-whitespace-in-astro-components/</link>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/withastro/astro/issues/5737&quot;&gt;A closed issue on GitHub&lt;/a&gt;
appears to still be occurring&lt;/li&gt;
&lt;li&gt;Forcing your code onto a single line is a workaround&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When your Astro code is formatted onto multiple lines, the resulting markup from
the Astro compiler includes a whitespace. This is noticeable when you have a
list of links that are underlined:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; Link 1 &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; Link 2 &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;!-- Underline in markdown --&gt;
&lt;p&gt;Result: &lt;ins&gt;Link 1 &lt;/ins&gt;   &lt;ins&gt;Link 2&lt;/ins&gt;&lt;/p&gt;
&lt;p&gt;But if the markup is on a single line, then the issue goes away:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Link 1&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Link 2&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result: &lt;ins&gt;Link 1&lt;/ins&gt;   &lt;ins&gt;Link 2&lt;/ins&gt;&lt;/p&gt;
&lt;p&gt;I have faked the output for this article, but you can
&lt;a href=&quot;https://stackblitz.com/edit/github-wg8oqd?file=src/pages/index.astro&quot;&gt;see a live reproduction&lt;/a&gt;
of this behavior on StackBlitz.&lt;/p&gt;
&lt;p&gt;To workaround this issue, you need force your markup onto a single line. Let’s
look at a real-world example element with multiple attributes. Your code
formatter will spread it over multiple lines:&lt;/p&gt;
&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;aria-current&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Astro&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;page&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To force this code onto a single line, we need to refactor. Create variables to
represent attributes and children with short names, and then pass them to the
element:&lt;/p&gt;
&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&#39;aria-current&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Astro&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pathname &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;page&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;label
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token spread&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code is objectively worse (and might create a TypeScript warning that you
need to ignore), but it will fix the whitespace issue. Hopefully the Astro team
can fix the issue in the compiler and make this workaround unnecessary.&lt;/p&gt;
</description>
      <pubDate>Thu, 02 Mar 2023 10:59:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-trailing-whitespace-in-astro-components/</guid>
    </item>
    <item>
      <title>Farewell Create React App</title>
      <link>https://seanmcp.com/articles/farewell-create-react-app/</link>
      <description>&lt;ul&gt;
&lt;li&gt;The React team is looking to sunset “Create React App” as a project scaffold&lt;/li&gt;
&lt;li&gt;They are leaning towards turning it into a “launcher” which would suggest a
list of recommended frameworks&lt;/li&gt;
&lt;li&gt;This is part of a greater shift away from client-side rendered applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I learned React while attending a coding bootcamp in 2017. With the help of
Create React App, I was able to learn the syntax and features of the library
without needing to understand Webpack or Babel. It was a valuable tool for
learning React, and I’m thankful that it existed.&lt;/p&gt;
&lt;p&gt;Today I rarely spin up new React applications – even for pet projects. But if I
did, I would use Vite instead of CRA. The ecosystem for front-end project
scaffolds has changed significantly in the last six years, and CRA hasn’t kept
up with the times. I think that it makes sense for the React team to move on
from it and let the community solutions and frameworks pick up the slack.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/reactjs/reactjs.org/pull/5487#issuecomment-1409720741&quot;&gt;The discussion also mentions&lt;/a&gt;
that server-side rendering and static-site generation are two critical areas of
front-end development going forward. The use cases for client-side rendered apps
are limited, and
&lt;a href=&quot;https://infrequently.org/2023/02/the-market-for-lemons/&quot;&gt;the weaknesses are now well documented&lt;/a&gt;.
Instead of the React team having one official approach (CRA) and a bunch of
official ones (Next, Astro, Vite, &lt;em&gt;etc&lt;/em&gt;.) for using the library, they want to be
more agnostic. This is a good move for the health of the web.&lt;/p&gt;
&lt;p&gt;Thank you for your service, Create React App. Enjoy retirement.&lt;/p&gt;
</description>
      <pubDate>Tue, 28 Feb 2023 15:03:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/farewell-create-react-app/</guid>
    </item>
    <item>
      <title>Valid JavaScript variable names</title>
      <link>https://seanmcp.com/articles/valid-javascript-variable-names/</link>
      <description>&lt;p&gt;I’ve been working on a little library to help build little JavaScript
applications. Something to fill the gap for me between little scripts and
reaching for a framework like Svelte.&lt;/p&gt;
&lt;p&gt;While designing the API, I’ve found myself searching for obscure but technically
valid JS variable names to distinguish my library from the standard HTML element
properties. Is &lt;code&gt;@id&lt;/code&gt; valid? What about &lt;code&gt;$id&lt;/code&gt;? Can I use a &lt;code&gt;:&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;These questions are easy to answer by opening the console, but wouldn’t it be
nice to have a little tool to validate JavaScript variable names? Thankfully it
already exists:
&lt;a href=&quot;https://mathiasbynens.be/&quot;&gt;Mathias Bynen’s&lt;/a&gt;&lt;a href=&quot;https://mothereff.in/js-variables&quot;&gt;JavaScript variable name validator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With it you can quickly validate a variable while maintaining your flow. And if
you’re curious as to why,
&lt;a href=&quot;https://mathiasbynens.be/notes/javascript-identifiers-es6&quot;&gt;he has an article explaining the specifications&lt;/a&gt;.
While writing this, I noticed that
&lt;a href=&quot;https://mothereff.in/&quot;&gt;the main site has a bunch of other little tools&lt;/a&gt; for you
to checkout. (Pardon the name 🙊)&lt;/p&gt;
&lt;p&gt;Up the web!&lt;/p&gt;
</description>
      <pubDate>Sat, 25 Feb 2023 11:15:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/valid-javascript-variable-names/</guid>
    </item>
    <item>
      <title>Migrating to IndieWeb.social</title>
      <link>https://seanmcp.com/articles/migrating-to-indiewebsocial/</link>
      <description>&lt;p&gt;Today I migrated from &lt;a href=&quot;http://fosstodon.org&quot;&gt;fosstodon.org&lt;/a&gt; to
&lt;a href=&quot;https://indieweb.social&quot;&gt;indieweb.social&lt;/a&gt;. You can find me
&lt;a href=&quot;https://indieweb.social/@seanmcp&quot;&gt;@seanmcp@indieweb.social&lt;/a&gt;. In the process, I
found
&lt;a href=&quot;https://codingitwrong.com/2022/10/10/migrating-a-mastodon-account.html&quot;&gt;this guide by Josh Justice&lt;/a&gt;
to be really helpful.&lt;/p&gt;
&lt;p&gt;Why migrate? I initially migrated to Fosstodon from
&lt;a href=&quot;http://Mastodon.social&quot;&gt;Mastodon.social&lt;/a&gt; because I wanted an instance that was
more focused on technology. I dabble in open-source maintenance, so the FOSS
part of Fosstodon was intriguing.&lt;/p&gt;
&lt;p&gt;What I did not realize at the time is that FOSS is its own thing. There was tons
of discussion about Linux distros and desktop environments that went way over my
head.
&lt;a href=&quot;https://seanmcp.com/series#trying-linux-2022&quot;&gt;I’m a general fan in free and open-source software&lt;/a&gt;
but not big enough.&lt;/p&gt;
&lt;p&gt;I’m more interested in the indie-web scene than FOSS, so I’m thinking that the
new instance will be a better fit. But we’ll see! The grass is always greener 🌱&lt;/p&gt;
&lt;p&gt;Following account were migrated and links here have been updated.
&lt;a href=&quot;https://indieweb.social/@seanmcp&quot;&gt;Come say hi!&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>Thu, 16 Feb 2023 14:38:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/migrating-to-indiewebsocial/</guid>
    </item>
    <item>
      <title>Publishing a Qwik component</title>
      <link>https://seanmcp.com/articles/publishing-a-qwik-component/</link>
      <description>&lt;p&gt;After hearing creator Miško Hevery on every front-end podcast that I listen to,
I decided to give his new Qwik library a look. My canonical approach to learning
a new library is creating a &lt;code&gt;*-emoji&lt;/code&gt; component that wraps emojis with the
appropriate HTML attributes for accessibility.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;npm create qwik@latest&lt;/code&gt;, I was able to scaffold a Qwik component library
quickly. Then it was a matter of writing the component using Qwik’s &lt;code&gt;component$&lt;/code&gt;
function and exporting things in the right places.&lt;/p&gt;
&lt;p&gt;To speak nothing of Qwik’s other features, it was a breeze writing my first
component. It looks and feels just like React (thanks JSX!), and I only needed
to reference the documentation one time to confirm how props worked. The project
setup was great, and helped me identify some Qwik-specific TypeScript issues
before I published the library.&lt;/p&gt;
&lt;p&gt;Overall, publishing a Qwik component was a smooth and painless process. Kudos to
the Qwik team for making it a great developer experience.&lt;/p&gt;
&lt;p&gt;You can checkout my &lt;a href=&quot;https://npm.im/qwik-emoji&quot;&gt;Qwik emoji library on npm&lt;/a&gt;, or
install it yourself with:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; i qwik-emoji&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Onward!&lt;/p&gt;
</description>
      <pubDate>Mon, 13 Feb 2023 11:25:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/publishing-a-qwik-component/</guid>
    </item>
    <item>
      <title>Fix Astro dev server hanging with new collections API</title>
      <link>https://seanmcp.com/articles/fix-astro-dev-server-hanging-with-new-collections-api/</link>
      <description>&lt;p&gt;This week I was in the process of upgrading this site to
&lt;a href=&quot;https://astro.build/blog/astro-2/&quot;&gt;Astro v2&lt;/a&gt; and its new features. Upgrading to
version 2 went smoothly, but I encountered a frustrating problem adopting the
&lt;a href=&quot;https://docs.astro.build/en/guides/content-collections/&quot;&gt;new content collections API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I repeatedly hit an issue where the Astro dev server will hang after calling
&lt;code&gt;getCollection&lt;/code&gt; from &lt;code&gt;astro:content&lt;/code&gt;. The hardest part is that there are no
errors in the browser or console – just an endless spinner when you try to load
the page.&lt;/p&gt;
&lt;p&gt;I though that maybe a solution was to
&lt;a href=&quot;https://vitejs.dev/guide/dep-pre-bundling.html#caching&quot;&gt;manually clear Vite’s cache&lt;/a&gt;
before restarting the dev server, which was as sophisticated as
&lt;code&gt;rm -rf node_modules/.vite&lt;/code&gt;. This &lt;em&gt;may have&lt;/em&gt; resolved the issue a few times, but
everything was so intermittent that I can’t say for sure.&lt;/p&gt;
&lt;p&gt;On the Astro Discord, I posed a question to see if anyone else had encountered a
similar issue. One of the devs linked to
&lt;a href=&quot;https://github.com/withastro/astro/issues/6173&quot;&gt;this issue on GitHub&lt;/a&gt; which
described a similar scenario. The problem there is a page &lt;em&gt;and&lt;/em&gt; its layout
calling the same collection.&lt;/p&gt;
&lt;p&gt;Looking back to my code, I couldn’t see where that was happening, but I decided
to remove all the &lt;code&gt;layout&lt;/code&gt; prop from the entries in that collection. (I wanted
to do this anyway, since moving to content collections made a separate layout
unnecessary.)&lt;/p&gt;
&lt;p&gt;After those changes, the hanging dev server issue resolved itself. I’m glad to
have found a fix, thought it would probably be good for Astro to recommend &lt;em&gt;not&lt;/em&gt;
using layouts for content collections.&lt;/p&gt;
&lt;p&gt;Onward!&lt;/p&gt;
</description>
      <pubDate>Sat, 11 Feb 2023 17:08:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-astro-dev-server-hanging-with-new-collections-api/</guid>
    </item>
    <item>
      <title>Be careful parsing formatted numbers in JavaScript</title>
      <link>https://seanmcp.com/articles/be-careful-parsing-formatted-numbers-in-javascript/</link>
      <description>&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/caution.jpg&quot; alt=&quot;a hole in the sidewalk filed with a caution cone&quot;&gt;&lt;/p&gt;
&lt;p&gt;I was working on a script recently and ran into an unexpected issue. The work
involved parsing a number-range string into an array of numbers, &lt;em&gt;e.g.&lt;/em&gt; &amp;quot;1-100&amp;quot;
into &lt;code&gt;[1,100]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My first instinct was to reach for &lt;code&gt;parseInt&lt;/code&gt; with something like:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1-100&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [1, 100]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This worked nicely until I rant into formatted numbers in the dataset:
&amp;quot;1,000-2,000&amp;quot;. Instead of parsing the strings into the expected numbers,
&lt;code&gt;parseInt&lt;/code&gt; seems to treat the commas as decimals:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1,000-2,000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [1, 2]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, &lt;code&gt;parseFloat&lt;/code&gt; and the &lt;code&gt;Number&lt;/code&gt; constructor similarly struggle with
formatted numbers:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1,000-2,000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [1, 2]&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&quot;1,000-2,000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [NaN, NaN]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s interesting to me that &lt;code&gt;Number&lt;/code&gt; returns &lt;code&gt;NaN&lt;/code&gt;, but
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/Number#return_value&quot;&gt;MDN says you probably shouldn&#39;t be using it like this anyway&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The solution is to remove the commas before parsing. There are a few methods to
do this, but &lt;code&gt;String.replace&lt;/code&gt; will work nicely:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1,000-2,000&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&#39;re curious, swapping the commas for underscores –
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#numeric_separators&quot;&gt;the approved numeric separator&lt;/a&gt;
– doesn&#39;t work either:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1_000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There might be an optimal solution that handles numbers formatted for different
locales, &lt;em&gt;e.g.&lt;/em&gt; &amp;quot;1.000,00&amp;quot; and &amp;quot;1,000.00&amp;quot;, so
&lt;a href=&quot;https://seanmcp.com/articles/be-careful-parsing-formatted-numbers-in-javascript/#comment-link&quot;&gt;please send me a message if you know of one&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Tue, 20 Dec 2022 14:14:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/be-careful-parsing-formatted-numbers-in-javascript/</guid>
    </item>
    <item>
      <title>New command palette</title>
      <link>https://seanmcp.com/articles/new-command-palette/</link>
      <description>&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/command-palette.png&quot; alt=&quot;Command Palette V1&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://seanmcp.com/articles/are-command-bars-the-future/&quot;&gt;﻿Last month, I wrote about the new &amp;quot;command bars&amp;quot; UI pattern&lt;/a&gt;,
and ever since the idea of adding one to this site has been kicking around my
head. The design doesn&#39;t support lots of links in the header, so an &amp;quot;over UI&amp;quot;
for navigating seemed like a decent choice.&lt;/p&gt;
&lt;p&gt;Y﻿esterday I added a new &lt;kbd&gt;command/control&lt;/kbd&gt; &lt;kbd&gt;k&lt;/kbd&gt; command palette
to this site. You can activate it by typing the keyboard shortcut or clicking
the magnifying-glass icon in the header. You can exit the palette by pressing
&amp;quot;Escape&amp;quot; or tapping on the overlay.&lt;/p&gt;
&lt;p&gt;The component is built using Astro and some styles and TypeScript, which should
make it portable to other sites once I iron out all of the bugs. I still get a
kick out of how easy it is to build UI with Astro components. Well done, Astro
team!&lt;/p&gt;
&lt;p&gt;C﻿urrently your query has to directly match the content available, but I&#39;m
planning to add fuzzy matching in the future. In the meantime, I&#39;m hoping that
it simplifies the process of surfacing content on my site.&lt;/p&gt;
&lt;p&gt;H﻿appy commanding!&lt;/p&gt;
</description>
      <pubDate>Thu, 15 Dec 2022 11:17:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/new-command-palette/</guid>
    </item>
    <item>
      <title>Fix &quot;package esbuild-linux-64 could not be found&quot; error on Netlify</title>
      <link>https://seanmcp.com/articles/fix-package-esbuild-linux-64-could-not-be-found-error-on-netlify/</link>
      <description>&lt;p&gt;This morning my website&#39;s builds started failing on Netlify. Checking the deploy
logs, I saw the following error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10:29:09 AM: [astro:jsx] The package &amp;quot;esbuild-linux-64&amp;quot; could not be found, and is needed by esbuild.
10:29:09 AM: If you are installing esbuild with npm, make sure that you don&#39;t specify the
&amp;quot;--no-optional&amp;quot; flag. The &amp;quot;optionalDependencies&amp;quot; package.json feature is used
10:29:09 AM: by esbuild to install the correct binary executable for your current platform.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/evanw/esbuild/issues/1819&quot;&gt;There is a closed issue about it in &lt;code&gt;esbuild&lt;/code&gt;&lt;/a&gt;,
but there wasn&#39;t a definite fix. Seems to be a problem related to dependencies
built for different platforms.&lt;/p&gt;
&lt;p&gt;I had recently encountered some merge conflicts in &lt;code&gt;package-lock.json&lt;/code&gt; (RIP) and
thought that might have been it. But generating the file again had no effect on
the error, and neither did running &lt;code&gt;npm audit fix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The last thing I tried was to delete &lt;code&gt;package-lock.json&lt;/code&gt; entirely and commit
that. Without the lock file, Netlify was able to install the correct
dependencies and deploy the site. So... solved?&lt;/p&gt;
&lt;p&gt;That will work for me and my personal site, but if you are working on project
with multiple developers in a more high-stakes environment, then you&#39;ll probably
want to keep looking for a more permanent solution.&lt;/p&gt;
&lt;p&gt;I&#39;ll make sure to update this article if the issue arises again.&lt;/p&gt;
&lt;p&gt;Happy debugging!&lt;/p&gt;
</description>
      <pubDate>Wed, 14 Dec 2022 14:37:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-package-esbuild-linux-64-could-not-be-found-error-on-netlify/</guid>
    </item>
    <item>
      <title>Portable custom search engines</title>
      <link>https://seanmcp.com/articles/portable-custom-search-engines/</link>
      <description>&lt;p&gt;Custom search engines (or site search) are
&lt;a href=&quot;https://zapier.com/blog/add-search-engine-to-chrome/&quot;&gt;a useful tool for improving your workflow in the browser&lt;/a&gt;.
By configuring shortcuts and URLs, you&#39;re able to search sites or complete paths
quickly and efficiently. Plus, it&#39;s totally customizable.&lt;/p&gt;
&lt;p&gt;I﻿ have a few setup to query common documentation sites or complete common URLs.
They save me time, clicks, and/or cognitive load and are an important part of my
workflow.&lt;/p&gt;
&lt;p&gt;E﻿ven though Chrome browsers and Firefox all support custom search engines,
there isn&#39;t a good way to port your settings from one browser to the next.
They&#39;re hidden away in a special settings location which doesn&#39;t get exported
alongside history and bookmarks when you move.&lt;/p&gt;
&lt;p&gt;A﻿s a front-end developer, I spend a lot of time hoping between browsers. And
the inability to use my custom search engines everywhere has been a point of
frustration. To solve this, I created a web-based solution that gives me the
features I want from custom search engines without getting locked in to any
particular browser.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/seanmcp/jean&quot;&gt;﻿Jean is a portable custom search engine&lt;/a&gt; that
you control. Search engines are added to a simple file using a CSV-like syntax
for labels, shortcuts, and URLs. Then load the page in your browser and get
searching!&lt;/p&gt;
&lt;p&gt;Jean was designed to work with GitHub Pages, but for a little more privacy you
can load it directly from your computer – no HTTP server required! Just copy the
whole path into your browser and bookmark it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://seanmcp.github.io/jean/&quot;&gt;﻿You can checkout a live version of Jean here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;F﻿or a little extra power, you can use Jean&#39;s query API to forward shortcuts
through Jean. Just add a single custom search engine to your browser: -﻿ Label:
&amp;quot;Jean&amp;quot; -﻿ Shortcut: &amp;quot;j&amp;quot; (or whatever you want) -﻿ URL:
&amp;quot;&lt;your-jean-location&gt;/?q=%s&amp;quot;&lt;/your-jean-location&gt;&lt;/p&gt;
&lt;p&gt;N﻿ow you can search using any of your custom search engines by using Jean as a
proxy:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;j wk Search engines&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A﻿fter porting all of my custom search engines over to Jean, I was able to
switch my Chrome work setup to Edge in about two minutes. Blazin&#39;!&lt;/p&gt;
&lt;p&gt;T﻿o create your own portable custom search engine,
&lt;a href=&quot;https://github.com/seanmcp/jean/fork&quot;&gt;fork the Jean repository&lt;/a&gt; and add your
favorites to &lt;code&gt;engines.js&lt;/code&gt;. And that&#39;s it; you&#39;re read to start searching.&lt;/p&gt;
&lt;p&gt;L﻿et me know what you think, and
&lt;a href=&quot;https://github.com/seanmcp/jean/issues&quot;&gt;file an issue if you find a bug&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;H﻿appy searching!&lt;/p&gt;
</description>
      <pubDate>Mon, 05 Dec 2022 15:49:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/portable-custom-search-engines/</guid>
    </item>
    <item>
      <title>A first look at Static CMS with Astro</title>
      <link>https://seanmcp.com/articles/a-first-look-at-static-cms-with-astro/</link>
      <description>&lt;p&gt;The first version of &lt;a href=&quot;https://staticjscms.netlify.app&quot;&gt;Static CMS&lt;/a&gt;, a community
fork of &lt;a href=&quot;https://netlifycms.org&quot;&gt;Netlify CMS&lt;/a&gt;, is scheduled to drop today. As a
Netlify user and a general fan of Netlify CMS, I am excited to see what the
community can do iterate on a useful product.&lt;/p&gt;
&lt;p&gt;While we wait for that initial release, I wanted to explore what it would take
to switch this &lt;a href=&quot;https://astro.build&quot;&gt;Astro&lt;/a&gt; site from Netlify CMS to Static CMS.&lt;/p&gt;
&lt;p&gt;First, I created a new admin route within the &lt;code&gt;public/&lt;/code&gt; directory with
&lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;config.yml&lt;/code&gt; files:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; public/x-admin
&lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; public/x-admin/index.html public/x-admin/config.yml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I opted for
&lt;a href=&quot;https://staticjscms.netlify.app/docs/add-to-your-site-cdn&quot;&gt;the CDN hosting option&lt;/a&gt;
(mostly because it was simpler), which involved pasting the following code block
into &lt;code&gt;index.html&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;utf-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;width=device-width, initial-scale=1.0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Content Manager&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Include the script that builds the page and powers Static CMS --&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://unpkg.com/@staticcms/core@%5E1.0.0/dist/static-cms-core.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
      window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CMS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Loading the route, and I hit issues where &lt;code&gt;window.CMS&lt;/code&gt; was undefined. I tried
tweaking the version of the script from the snippet and eventually got it
working:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://unpkg.com/@staticcms/core@latest/dist/static-cms-core.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that updated, I moved on to configuration. I tried copying my Netlify CMS
&lt;code&gt;config.yml&lt;/code&gt; into the new admin directory, and it loaded right up! It&#39;s nice
when things go smoothly.&lt;/p&gt;
&lt;p&gt;I was able to view all of my articles and create a new draft (I&#39;m using Static
CMS to write this article right now). The only configuration that didn&#39;t
obviously work was the &amp;quot;list&amp;quot; widget. I use this to set the tags for an article,
but there was nothing rendered in the UI.&lt;/p&gt;
&lt;p&gt;I tweaked the config a little for &amp;quot;list&amp;quot; and got &lt;em&gt;something&lt;/em&gt; to render, though
I&#39;m not sure it would work correctly for me:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Tags&quot;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tags&quot;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;widget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;list&quot;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;fields&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Tag&quot;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tag&quot;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;widget&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I tried to test what the resulting data would look like, but when I attempted to
publish I got the following error:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Failed to persist entry: API_ERROR: &amp;quot;params.options.useWorkflow&amp;quot; is required&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There isn&#39;t any reference to that in the documentation or
&lt;a href=&quot;https://github.com/StaticJsCMS/static-cms/issues?q=is%3Aissue+params.options.useWorkflow+&quot;&gt;GitHub issues&lt;/a&gt;,
so I was feeling kind of stuck. But after a little digging, I found
&lt;a href=&quot;https://github.com/StaticJsCMS/static-cms-eleventy-netlify-template/blob/main/src/admin/config.yml#L11&quot;&gt;this comment in one of the example templates&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Please run &quot;npx static-cms-proxy-server&quot; for local backend&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I didn&#39;t see a reference to that in the documentation, so I ran that in the
terminal and received the following:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ npx static-cms-proxy-server
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; ERR&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; Cannot convert undefined or null to object&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Turns out
&lt;a href=&quot;https://www.npmjs.com/package/static-cms-proxy-server&quot;&gt;that package does not exist yet&lt;/a&gt;.
There is a reason why they call it the &amp;quot;bleeding edge.&amp;quot;&lt;/p&gt;
&lt;p&gt;I could go on, but this felt like a fair enough attempt at getting it to work.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/a-first-look-at-static-cms-with-astro/#conclusion&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Conclusion”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I&#39;m excited to see what the maintainers of Static CMS can do to carry the torch
of Netlify CMS. But at this stage, it still feels very raw. To illustrate that
point, I started writing this article in Static CMS but am finishing it in
Netlify CMS.&lt;/p&gt;
&lt;p&gt;Maybe if you use one of the starter templates you will have more success. For
now, I&#39;m going to be watching the development from the sidelines.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Wed, 30 Nov 2022 24:43:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/a-first-look-at-static-cms-with-astro/</guid>
    </item>
    <item>
      <title>Astro components do not merge HTML attributes</title>
      <link>https://seanmcp.com/articles/astro-component-do-not-merge-html-attributes/</link>
      <description>&lt;p&gt;Over the past month I have been enjoying working in the
&lt;a href=&quot;https://astro.build&quot;&gt;Astro&lt;/a&gt; ecosystem recently, and have been working on some
simple community packages.&lt;/p&gt;
&lt;p&gt;I&#39;ve learned that Astro merges component props and element attributes
differently, so I&#39;m writing this short PSA to help myself and other Astro devs
in the future.&lt;/p&gt;
&lt;p&gt;First, some terminology:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.astro.build/en/core-concepts/astro-components/#component-props&quot;&gt;Props&lt;/a&gt;
are the data or properties that we pass to components&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes&quot;&gt;Attributes&lt;/a&gt;
are the data that we pass directly to HTML elements&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We might think of these interchangeably in most component-based frameworks, but
as we will see here they are different in Astro components.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;props%3A-left-to-right&quot; tabindex=&quot;-1&quot;&gt;Props: left-to-right&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/astro-component-do-not-merge-html-attributes/#props%3A-left-to-right&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Props: left-to-right”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;For props, &lt;strong&gt;Astro merges from left-to-right&lt;/strong&gt;. This means that a prop on the
left-side of a component call will be overwritten by the prop with the same name
on the right:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;&lt;Example side=&quot;left&quot;&gt;
&lt;!-- side: &quot;right&quot; --&gt;&lt;/Example&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting &lt;code&gt;side&lt;/code&gt; prop within the &lt;code&gt;Example&lt;/code&gt; component will be &amp;quot;right&amp;quot;.&lt;/p&gt;
&lt;p&gt;The above example is a little contrived, but you can imagine a scenario where
you are creating a component that allows overriding default values:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;&lt;ElementCard element=&quot;Hydrogen&quot; {...Astro.props}=&quot;&quot;&gt;&lt;/ElementCard&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;attributes%3A-no-merging&quot; tabindex=&quot;-1&quot;&gt;Attributes: no merging&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/astro-component-do-not-merge-html-attributes/#attributes%3A-no-merging&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Attributes: no merging”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;However, &lt;strong&gt;Astro does not merge attributes on HTML elements&lt;/strong&gt;. So if you have
two identical attributes passed to an element, that is what goes to the DOM.
Browsers typically ignore any duplicate attributes, so the prevailing value is
the first from left-to-right:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;&lt;input type=&quot;text&quot;&gt;
&lt;!-- type: &quot;text&quot; --&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting &lt;code&gt;type&lt;/code&gt; attribute for &lt;code&gt;input&lt;/code&gt; element will be &amp;quot;text&amp;quot;.&lt;/p&gt;
&lt;p&gt;If you want to create a component that allows overriding default attribute
values, then you need to spread them on &lt;em&gt;the left-side of the element&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;&lt;input {...Astro.props}=&quot;&quot; type=&quot;text&quot;&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This behavior might be the opposite of what you expect. For a counter example,
React merges both props and attributes. But whatever the reason for the
difference, it&#39;s important to remember.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;tl%3Bdr&quot; tabindex=&quot;-1&quot;&gt;tl;dr&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/astro-component-do-not-merge-html-attributes/#tl%3Bdr&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “tl;dr”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In Astro you should spread props to components on the right, and elements on the
left:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;&lt;Component default=&quot;value&quot; {...Astro.props}=&quot;&quot;&gt;
&lt;element {...Astro.props}=&quot;&quot; default=&quot;value&quot;&gt;&lt;/element&gt;&lt;/Component&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://stackblitz.com/edit/withastro-astro-eryebq?file=src/pages/index.astro&quot;&gt;You can see this behavior in action live on StackBlitz&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;That&#39;s all. Hope it was helpful to you, and memorable for me!&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Tue, 29 Nov 2022 14:36:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/astro-component-do-not-merge-html-attributes/</guid>
    </item>
    <item>
      <title>Run Netlify CMS and your dev server in one command</title>
      <link>https://seanmcp.com/articles/run-netlify-cms-and-your-dev-server-in-one-command/</link>
      <description>&lt;p&gt;If you&#39;re using &lt;a href=&quot;https://netlifycms.org&quot;&gt;Netlify CMS&lt;/a&gt;, there is a command that
you can run to load it in development:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;npx netlify-cms-proxy-server&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is useful, but it needs to be run in a separate terminal window to your
development server. I use VS Code, which has easy split terminal windows, but
it&#39;s still a little annoying to have to fire up two processes when you want to
get to work.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Window 1&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run dev&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Window 2&lt;/span&gt;
npx netlify-cms-proxy-server&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An ideal solution would be to run a single command that runs both scripts in
parallel, so that you can focus on working as opposed to setting things up.&lt;/p&gt;
&lt;p&gt;Thankfully for us,
&lt;a href=&quot;https://npm.im/npm-run-all&quot;&gt;&lt;code&gt;npm-run-all&lt;/code&gt; is the perfect solution&lt;/a&gt; for this.
First we install it as a dev dependency:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; i &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; npm-run-all&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add a new script to our &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;cms&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npx netlify-cms-proxy-server&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;dev&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;astro dev&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;dev:cms&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm-run-all --parallel cms dev&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when you want to run Netlify CMS alongside your development server, you just
need to a single command:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run dev:cms&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Tue, 29 Nov 2022 10:54:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/run-netlify-cms-and-your-dev-server-in-one-command/</guid>
    </item>
    <item>
      <title>Fix Netlify Dev&#39;s &#39;Multiple possible start commands found&#39; issue</title>
      <link>https://seanmcp.com/articles/fix-netlify-devs-multiple-possible-start-commands-found-issue/</link>
      <description>&lt;p&gt;Netlify Dev attempts to guess what framework your project is using and what
commands it should run in development.&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ netlify dev

◈ Netlify Dev ◈
◈ Ignored general context &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; var: &lt;span class=&quot;token environment constant&quot;&gt;LANG&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;defined &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
◈ Ignored general context &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; var: &lt;span class=&quot;token environment constant&quot;&gt;LC_ALL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;defined &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
? Multiple possible start commands found &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Use arrow keys or &lt;span class=&quot;token builtin class-name&quot;&gt;type&lt;/span&gt; to search&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
❯ &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Astro&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;npm run dev&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Svelte&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;npm run dev&#39;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Svelte&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;npm run build&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.netlify.com/configure-builds/file-based-configuration/#netlify-dev&quot;&gt;Reading the Netlify documentation&lt;/a&gt;,
it seems like you should be able to resolve this by adding a &lt;code&gt;[dev]&lt;/code&gt; section to
your &lt;code&gt;netlify.toml&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;language-toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&amp;lt;!-- This doesn&#39;t work --&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key property&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run dev&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, that alone &lt;strong&gt;does not work&lt;/strong&gt;.
&lt;a href=&quot;https://github.com/netlify/cli/issues/410&quot;&gt;There is a &amp;quot;closed&amp;quot; issued that describes the behavior&lt;/a&gt;,
but essentially the Netlify CLI doesn&#39;t read the &lt;code&gt;command&lt;/code&gt; even though you&#39;ve
set it.&lt;/p&gt;
&lt;p&gt;Thankfully,
&lt;a href=&quot;https://github.com/netlify/cli/issues/410#issuecomment-1046147453&quot;&gt;someone contributed an actual solution&lt;/a&gt;
that only requires a few more details:&lt;/p&gt;
&lt;pre class=&quot;language-toml&quot;&gt;&lt;code class=&quot;language-toml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token table class-name&quot;&gt;dev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token key property&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run dev&quot;&lt;/span&gt;
    &lt;span class=&quot;token key property&quot;&gt;framework&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#custom&quot;&lt;/span&gt;
    &lt;span class=&quot;token key property&quot;&gt;targetPort&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;framework&lt;/code&gt; needs to be set to &lt;code&gt;&amp;quot;#custom&amp;quot;&lt;/code&gt; and you need to manually set the port
that your dev server typically runs on. With Astro, that is port &lt;code&gt;3000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With that configured, everything works as expected:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ npx netlify dev

◈ Netlify Dev ◈
◈ Ignored general context &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; var: &lt;span class=&quot;token environment constant&quot;&gt;LANG&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;defined &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
◈ Ignored general context &lt;span class=&quot;token function&quot;&gt;env&lt;/span&gt; var: &lt;span class=&quot;token environment constant&quot;&gt;LC_ALL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;defined &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
◈ Setting up &lt;span class=&quot;token builtin class-name&quot;&gt;local&lt;/span&gt; development server&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Tue, 29 Nov 2022 10:40:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-netlify-devs-multiple-possible-start-commands-found-issue/</guid>
    </item>
    <item>
      <title>Astro components for Netlify features</title>
      <link>https://seanmcp.com/articles/astro-components-for-netlify-features/</link>
      <description>&lt;p&gt;This morning, I released the first version of
&lt;code&gt;astro-netlify-components&lt;/code&gt;,&lt;a href=&quot;https://npm.im/astro-netlify-components&quot;&gt;a library of Astro components for Netlify&lt;/a&gt;.
I was about to start dogfooding the functionality in my own site, and I figured
I might as well share it with the world.&lt;/p&gt;
&lt;p&gt;There are two exported component at launch:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Form&amp;gt;&lt;/code&gt;: adds all the of the markup for
&lt;a href=&quot;https://docs.netlify.com/forms/setup/&quot;&gt;Netlify Forms&lt;/a&gt; with types and
validation&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;CMS&amp;gt;&lt;/code&gt;: a full-page component to render the
&lt;a href=&quot;https://www.netlifycms.org/&quot;&gt;Netlify CMS&lt;/a&gt; admin interface&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To add either component to your, add the package to your project:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; i astro-netlify-components&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, import the components and use in your Astro page:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;---
import CMS from &quot;astro-netlify-components/CMS.astro&quot;;
import Form from &quot;astro-netlify-components/Form.astro&quot;;
---&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CMS&lt;/code&gt; renders a full page, so import and invoke it on a page of its own:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;---
// src/pages/admin.astro
import CMS from &quot;astro-netlify-components/CMS.astro&quot;;
---

&lt;CMS&gt;&lt;/CMS&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Form&lt;/code&gt; expects children, so you could set up a contact form on your site like
this:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;---
// src/pages/contact.astro
import Form from &quot;astro-netlify-components/Form.astro&quot;;
---

&lt;Form name=&quot;contact&quot;&gt;
  &lt;label&gt;
    &lt;b&gt;Name&lt;/b&gt;
    &lt;input type=&quot;text&quot; name=&quot;name&quot; required=&quot;&quot;&gt;
  &lt;/label&gt;
  &lt;label&gt;
    &lt;b&gt;Email&lt;/b&gt;
    &lt;input type=&quot;email&quot; name=&quot;email&quot; required=&quot;&quot;&gt;
  &lt;/label&gt;
  &lt;label&gt;
    &lt;b&gt;Message&lt;/b&gt;
    &lt;textarea name=&quot;message&quot; required=&quot;&quot;&gt;&lt;/textarea&gt;
  &lt;/label&gt;
  &lt;button&gt;Submit&lt;/button&gt;
&lt;/Form&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;p&gt;If you want to give it a try, make sure to
&lt;a href=&quot;https://github.com/seanmcp/astro-netlify-components&quot;&gt;checkout the documentation&lt;/a&gt;
and
&lt;a href=&quot;https://github.com/seanmcp/astro-netlify-components/issues&quot;&gt;file any issues you encounter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Fri, 25 Nov 2022 11:26:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/astro-components-for-netlify-features/</guid>
    </item>
    <item>
      <title>Create a &quot;Dave Rupert&quot;-inspired activity graph</title>
      <link>https://seanmcp.com/articles/create-a-dave-rupert-inspired-activity-graph/</link>
      <description>&lt;call-out type=&quot;warn&quot;&gt;
&lt;p&gt;This article was written when &lt;a href=&quot;http://seanmcp.com&quot;&gt;seanmcp.com&lt;/a&gt; was powered by Astro. I have left the
content in place, but the activity graph described no longer renders.&lt;/p&gt;
&lt;/call-out&gt;
&lt;p&gt;I noticed on &lt;a href=&quot;https://daverupert.com/archive/&quot;&gt;Dave Rupert&#39;s website&lt;/a&gt; that he
had a little activity graph to illustrate how many articles he has written per
year over time.&lt;/p&gt;
&lt;p&gt;That seemed like a nice little feature, so I decided to try to recreate it for
my site. This is a little code walk through how I made it using in a custom
Astro component.&lt;/p&gt;
&lt;p&gt;First, I needed to grab all of the data to count. I have two main forms of
content on this site, &lt;a href=&quot;https://seanmcp.com/articles&quot;&gt;articles&lt;/a&gt; and &lt;a href=&quot;https://seanmcp.com/notes&quot;&gt;notes&lt;/a&gt;. Using Astro&#39;s
&lt;code&gt;glob()&lt;/code&gt; method, I was able to get that data and pass it into a sorting
function:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; articles &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getSortedContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Astro&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;glob&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;../pages/articles/*.{md,mdx}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; notes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getSortedContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Astro&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;glob&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;../../content/notes/*.{md,mdx}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;call-out type=&quot;info&quot;&gt;
&lt;p&gt;This code is all subject to change, so for the latest
&lt;a href=&quot;https://github.com/SeanMcP/seanmcp.com/blob/master/src/components/ActivityGraph.astro&quot;&gt;checkout the source on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/call-out&gt;
&lt;p&gt;Next, I knew that I needed to keep a record of some totals, so I created an
object to track the totals for each content-type by the year:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; yearCount&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Record&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; articles&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; notes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, I could loop through &lt;code&gt;articles&lt;/code&gt; and &lt;code&gt;notes&lt;/code&gt; and start
counting:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;articles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;article&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; year &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;article&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pubDate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFullYear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;yearCount&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; yearCount&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; articles&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; notes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  yearCount&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;articles&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

notes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;note&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; year &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;note&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frontmatter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pubDate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getFullYear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;yearCount&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; yearCount&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; articles&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; notes&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  yearCount&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;year&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;notes&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was far from DRY, but I didn&#39;t think it was worth refactoring at this
point.&lt;/p&gt;
&lt;p&gt;With the data ready, it was time to start rendering. I went with an ordered
list, &lt;code&gt;ol&lt;/code&gt;, with list items for each year. Within each &lt;code&gt;li&lt;/code&gt;, I have a label, and
two &lt;code&gt;span&lt;/code&gt;s to represent articles and notes.&lt;/p&gt;
&lt;p&gt;I tried to label things in a helpful manner, but I&#39;m sure there are
accessibility improvements to be made.&lt;/p&gt;
&lt;p&gt;The last bit of magic was finding a decent height for the most prolific year,
and then use that when calculating the individual &lt;code&gt;span&lt;/code&gt; heights. And thanks to
&lt;code&gt;Math.max()&lt;/code&gt;&#39;s API, this was pretty nice:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; highest &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;yearCount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;record&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;articles &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; record&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;notes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 16 * 4 or 64 is the maximum height for a year&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; multiplier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; highest&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all that set up, all I needed to do was iterate:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;&lt;ol&gt;
  {
    Object.entries(yearCount).map(([year, { articles, notes }]) =&gt; {
      const articlesLabel = `${articles} articles`;
      const notesLabel = `${notes} notes`;
      return (
        &lt;li&gt;
          &lt;div title=&quot;{String(articles&quot; +=&quot;&quot; notes)}=&quot;&quot;&gt;{year}&lt;/div&gt;
          &lt;span class=&quot;articles&quot; style=&quot;{{&quot; height:=&quot;&quot; articles=&quot;&quot; *=&quot;&quot; multiplier=&quot;&quot; +=&quot;&quot; &quot;px&quot;=&quot;&quot; }}=&quot;&quot; title=&quot;{articlesLabel}&quot;&gt;
            &lt;span class=&quot;--visually-hidden&quot;&gt;{articlesLabel}&lt;/span&gt;
          &lt;/span&gt;
          &lt;span class=&quot;notes&quot; style=&quot;{{&quot; height:=&quot;&quot; notes=&quot;&quot; *=&quot;&quot; multiplier=&quot;&quot; +=&quot;&quot; &quot;px&quot;=&quot;&quot; }}=&quot;&quot; title=&quot;{notesLabel}&quot;&gt;
            &lt;span class=&quot;--visually-hidden&quot;&gt;{notesLabel}&lt;/span&gt;
          &lt;/span&gt;
        &lt;/li&gt;
      );
    })
  }
&lt;/ol&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is certainly room for improvement, but I&#39;m happy with how it turned out.
Here it is in all its glory:&lt;/p&gt;
&lt;ActivityGraph&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;/ActivityGraph&gt;</description>
      <pubDate>Wed, 23 Nov 2022 18:48:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/create-a-dave-rupert-inspired-activity-graph/</guid>
    </item>
    <item>
      <title>Use your domain on Mastodon with Astro</title>
      <link>https://seanmcp.com/articles/use-your-domain-on-mastodon-with-astro/</link>
      <description>&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: The solution in this article still works, but I think using a
&lt;a href=&quot;https://www.hawksworx.com/blog/alias-your-mastodon-username-to-your-domain-with-one-netlify-config-setting/&quot;&gt;redirect as described here&lt;/a&gt;
is probably a better option.&lt;/p&gt;
&lt;p&gt;Maarten Balliauw shared a cool strategy for using your own custom domain as a
reference to your Mastodon account. He explains it better than I can summarize,
&lt;a href=&quot;https://blog.maartenballiauw.be/post/2022/11/05/mastodon-own-donain-without-hosting-server.html&quot;&gt;so take a look at his article first&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I wanted to try it out, but I&#39;d prefer if the process was automated in my site&#39;s
build process. Thankfully, &lt;a href=&quot;https://astro.build&quot;&gt;Astro&lt;/a&gt; has an API for
generating arbitrary files on build with
&lt;a href=&quot;https://docs.astro.build/en/core-concepts/endpoints/&quot;&gt;endpoints&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In your Astro site, create a new file called
&lt;code&gt;src/pages/.well-known/webfinger.ts&lt;/code&gt; and paste the following code block&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;INSTANCE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;indieweb.social&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;USERNAME&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;seanmcp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/**
 * This endpoint adds a webfinger JSON file to your site so that you can use
 * your domain as a reference to your Mastodon account.
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INSTANCE&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/.well-known/webfinger?resource=acct:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;USERNAME&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INSTANCE&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;call-out type=&quot;info&quot;&gt;
&lt;p&gt;Make sure to swap out the values for your Mastodon instance and username!&lt;/p&gt;
&lt;/call-out&gt;
&lt;p&gt;When you trigger a build, Astro will run the &lt;code&gt;get()&lt;/code&gt; function which grabs the
webfinger information from your Mastodon instance and outputs it in the correct
&lt;code&gt;/.well-known/webfinger&lt;/code&gt; location.&lt;/p&gt;
&lt;p&gt;With that in place, you can now use your domain as a reference to your Mastodon
account.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
      <pubDate>Fri, 18 Nov 2022 13:29:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/use-your-domain-on-mastodon-with-astro/</guid>
    </item>
    <item>
      <title>Are command bars the future?</title>
      <link>https://seanmcp.com/articles/are-command-bars-the-future/</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://maggieappleton.com/command-bar&quot;&gt;Maggie Appleton recently wrote about &amp;quot;Command K Bars&amp;quot;&lt;/a&gt;,
those command line bars that you pull up with a keyboard combination. In
addition to giving a lot of cool product recommendations, she explained the
pattern for designers:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Command bars are command-line bars that pop up in the middle of the screen
when you hit a certain keyboard shortcut.They&#39;re also known as &#39;command
palettes&#39;, &#39;command launchers&#39;, or &#39;omniboxes&#39; Traditionally CMD + K, hence
the moniker “Command K bars.” But CMD + E and CMD + / have also been strong
shortcut contenders.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Bars like this let users search through all the available commands in an
application. Rather than remembering which sub-sub-sub menu a function lives
in, users need only remember its name.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;They don&#39;t even have to remember its exact name. Fuzzy search can help them
find it by simply typing in similar names or related keywords. For example, if
I type “make” into a command bar, it&#39;s likely to show me any actions related
to creating new items. Even if “make” isn&#39;t part of the action name.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some notable examples of this in my line of work are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Slack &lt;kbd&gt;CMD + K&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;VS Code &lt;kbd&gt;CMD + P&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;Chrome DevTools &lt;kbd&gt;CMD + P&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;Notion &lt;kbd&gt;CMD + K&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;GitHub &lt;kbd&gt;CMD + K&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I, for one, absolutely love this pattern. It&#39;s so nice to be able to quickly
jump to a command without needing to remember where the button is in the UI or
even the exact name for it. These command bars definitely improve my workflow.&lt;/p&gt;
&lt;p&gt;However they feel like a very developer-focused pattern, extending to products
for companies that work in tech. I&#39;m skeptical at this point that the pattern is
ready for mainstream products.&lt;/p&gt;
&lt;p&gt;In a quick survey of popular information and social-media sites, I found no
command K bars.&lt;/p&gt;
&lt;p&gt;It&#39;s also worth noting that the command key is Mac-centric. In tech we can
probably get away with that since it has large sections that are dominated by
Mac users, but that isn&#39;t the case for products with broader audiences. Maybe
swapping command for control is sufficient, or maybe switching to the meta key
makes more sense. It might take time before a true standard emerges.&lt;/p&gt;
&lt;p&gt;I think command bars are a great pattern, and I&#39;m looking forward to using them
in more ways and on more sites. But I wouldn&#39;t prioritize that feature work
unless you are in an industry that caters to developers or the companies that
employ them.&lt;/p&gt;
&lt;p&gt;What do you think: are command bars the wave of the future? Let me know.&lt;/p&gt;
&lt;p&gt;Happy interacting!&lt;/p&gt;
</description>
      <pubDate>Thu, 17 Nov 2022 11:14:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/are-command-bars-the-future/</guid>
    </item>
    <item>
      <title>Node.js is great for scripting</title>
      <link>https://seanmcp.com/articles/nodejs-is-great-for-scripting/</link>
      <description>&lt;p&gt;This week I was working on a project that reads 6.4 MB of text files (the
complete English Bible), does some processing and computation, and then outputs
JSON data. You can see
&lt;a href=&quot;https://github.com/seanmcp/shama&quot;&gt;result of that work on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In times past, I&#39;ve felt pressure to reach for a &amp;quot;proper scripting language&amp;quot;
like Python or a more performant one like Go. But I feel like we&#39;ve reached the
point where Node.js is a great choice for scripting.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JavaScript is everywhere&lt;/strong&gt;. You can find tutorials and examples for every
conceivable task for JS. And by and large, the code that works in the browser
will work in Node.js too.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript is forgiving&lt;/strong&gt;. When I&#39;m writing a script, it&#39;s usually for a
specific and personal use case. I don&#39;t want to spend a lot of time writing
syntax or worrying about types. And thankfully, JavaScript doesn&#39;t care about
that either.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The ecosystem is huge&lt;/strong&gt;. There are over one million npm packages, so the
chances are good that there is a solution available for whatever problem you
have. And thanks to JS being everywhere, there are countless guides to adding
dependencies to your project.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node.js is readable&lt;/strong&gt;. Thanks to JS&#39; async/await and sync functions from
Node.js&#39; standard libraries, writing a script that reads multiple
files/directories and then writes to others is pretty straightforward. No more
chaining callbacks!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node.js supports ESM&lt;/strong&gt;. Node.js supports ES modules with either the
&lt;code&gt;type: module&lt;/code&gt; flag in &lt;code&gt;package.json&lt;/code&gt; or the &lt;code&gt;.mjs&lt;/code&gt; extension. Maybe this is a
bigger deal for me personally, but the ability to import and export modules
without needing to think about &lt;code&gt;require()&lt;/code&gt; or &lt;code&gt;module.exports&lt;/code&gt; is pretty nice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node.js is fast&lt;/strong&gt;. That project I mentioned at the top? The Node.js script
that I wrote (which was not optimized for performance) ran in less than a
second. 6.4 MB in &amp;lt; 1 second! I&#39;m not saying that Node.js is the fastest
option, but for your typical scripting needs: it&#39;s more than fast enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;m not arguing that everyone should be using Node.js for scripting, nor that it
is the best solution for every problem in every environment. And if you prefer
Rust or Go or Ruby or WhatEver, go for it!&lt;/p&gt;
&lt;p&gt;But if you&#39;re a developer who is comfortable working in the JavaScript
ecosystem, don&#39;t be hesitant to reach for Node.js. It&#39;s a great option for your
next script.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Wed, 16 Nov 2022 14:21:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/nodejs-is-great-for-scripting/</guid>
    </item>
    <item>
      <title>There is no multi-tasking on the Raspberry Pi</title>
      <link>https://seanmcp.com/articles/there-is-no-multi-tasking-on-the-raspberry-pi/</link>
      <description>&lt;p&gt;Maybe this isn&#39;t fair to file under the &amp;quot;Trying Linux 2022&amp;quot; series since it
isn&#39;t commentary on the operating system writ large. However, it is a part of my
journey trying Linux and worth documenting.&lt;/p&gt;
&lt;p&gt;I have a Raspberry Pi 3 B+ (or something like that). I bought it about 4 years
ago with the goal of using it as a RetroPie, and it did that pretty well. Now
that I&#39;m here in 2022 trying to use this as a developer compuer, however, I&#39;m
starting to see some of the strains.&lt;/p&gt;
&lt;p&gt;With the Pi and Raspberry Pi OS, I can do approximately one tasks at the same
time. I can use the browser (Firefox ESR), VS Code, &lt;strong&gt;or&lt;/strong&gt; the Raspberry Pi
package manager. If I try to use two of these things at the same time, however,
the whole system grinds to a halt for minutes at a time. So I need to be really
careful &lt;em&gt;not&lt;/em&gt; to multitask while I&#39;m working.&lt;/p&gt;
&lt;p&gt;You hear some developers complain about how resource intensive modern
development has become. Browsers with all their extensions are big and bloated.
Electron-powered programs are slow and resource intensive. Running all of the
services locally takes more cores from your processor than computers had 20
years ago. I&#39;ve been largely sympathetic to those criticisms, but I haven&#39;t
really felt the pain because I&#39;ve always had a high-powered computer from my
employer that can manage the workload.&lt;/p&gt;
&lt;p&gt;Now that I&#39;m on a Raspberry Pi and trying to run a &amp;quot;simple&amp;quot; Node process &lt;em&gt;and&lt;/em&gt;
view it in the browser... I feel it.&lt;/p&gt;
&lt;p&gt;And maybe that is a good thing.&lt;/p&gt;
</description>
      <pubDate>Thu, 03 Nov 2022 11:14:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/there-is-no-multi-tasking-on-the-raspberry-pi/</guid>
    </item>
    <item>
      <title>Finding a Linux distro and software that work</title>
      <link>https://seanmcp.com/articles/finding-a-linux-distro-and-software-that-work/</link>
      <description>&lt;p&gt;I wrote
&lt;a href=&quot;https://seanmcp.com/articles/giving-linux-another-try&quot;&gt;yesterday&#39;s article about giving Linux another try&lt;/a&gt;
while things were still installing, &lt;em&gt;i.e.&lt;/em&gt; too soon. Here is everything that I
tried:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ubuntu Mate 22.04&lt;/strong&gt;: Installed but setup wouldn&#39;t complete (I probably tried
3-4 times).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ubunutu 22.04&lt;/strong&gt;: Installed and setup, but it was very slow and crashed
multiple times.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ubuntu Mate 22.04 (attempt 2)&lt;/strong&gt;: Installed and setup, but I was unable to
open Firefox.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lubuntu 20.04.5&lt;/strong&gt;: Couldn&#39;t get it to install on the microSD card. Maybe
because I renamed an &lt;code&gt;.iso&lt;/code&gt; file to &lt;code&gt;.img&lt;/code&gt;?
(&lt;a href=&quot;https://askubuntu.com/questions/1205768/how-to-convert-an-iso-file-to-img-format-in-linux&quot;&gt;Following this recommendation&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raspberry Pi OS&lt;/strong&gt;: It worked! 🎉&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the OS up and running, I moved on to installing software. Git was included
already, and I used &lt;code&gt;apt&lt;/code&gt; to install &lt;code&gt;nodejs&lt;/code&gt; and &lt;code&gt;vim&lt;/code&gt;. Brew doesn&#39;t work with
ARM devices, so I need to manage some software manually.&lt;/p&gt;
&lt;p&gt;I decided that it would probably be a good idea to use pnpm instead of npm on a
low-memory device. It required at least Node.js 14, but the latest version
available from &lt;code&gt;apt&lt;/code&gt; was 12.&lt;/p&gt;
&lt;p&gt;After going through the usual journey of trying to update Node.js, I ended up
&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;installing NVM&lt;/a&gt; and going with the new 18 LTS.
With that updated, I could install pnpm with: &lt;code&gt;npm i -g pnpm&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The included version of Chromium struggled to render emojis correctly, so I
opted for Firefox instead. I used the Raspberry Pi&#39;s package manager to install
&lt;code&gt;firefox-esr&lt;/code&gt; and it worked great. I made sure to install
&lt;a href=&quot;https://seanmcp.com/articles/awesome-browser-extensions&quot;&gt;uBlock Origin&lt;/a&gt; to hopefully help a bit
with performance.&lt;/p&gt;
&lt;p&gt;With all that in place, I now have a serviceable Linux machine for tinkering! It
still struggles a bit running multiple processes at the same time, but it&#39;s
definitely good enough for now.&lt;/p&gt;
</description>
      <pubDate>Wed, 02 Nov 2022 12:55:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/finding-a-linux-distro-and-software-that-work/</guid>
    </item>
    <item>
      <title>Giving Linux another try</title>
      <link>https://seanmcp.com/articles/giving-linux-another-try/</link>
      <description>&lt;p&gt;I felt inspired by
&lt;a href=&quot;https://www.heyhomepage.com/?module=blog&amp;amp;link=1&amp;amp;post=4&quot;&gt;an article by Hey Homepage&lt;/a&gt;
and recent &lt;a href=&quot;https://pca.st/3ypvfdke&quot;&gt;episode of The Changelog podcast&lt;/a&gt; to give
Linux another try. This description just sounds so nice:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For over a year now, I use a Raspberry Pi 4 (with 8GB of RAM) as my daily
desktop computer. I browse the internet, read and send e-mails, program
software, edit photos, create images, watch Youtube videos and play games on
it. Without any significant problems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So tonight I&#39;m dusting off the ol&#39; Raspberry Pi and trying a fresh installation
of Ubuntu Mate. Why Mate? Because it was recommended in the article above. The
latest time I needed a low-powered Ubuntu flavor I used Lubuntu, but that is
probably 10 years ago. Time flies!&lt;/p&gt;
&lt;p&gt;I don&#39;t expect to completely change my computing habits; as a front-end focused
developer I feel pretty compelled to stick with macOS. But I&#39;m looking forward
to peeking outside of the Apple ecosystem, even in a sandbox, to get a better
picture of the world out there in 2022.&lt;/p&gt;
&lt;p&gt;Please let me know if you have any suggestions, because I don&#39;t know what I&#39;m
doing. 😄&lt;/p&gt;
</description>
      <pubDate>Wed, 02 Nov 2022 24:35:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/giving-linux-another-try/</guid>
    </item>
    <item>
      <title>Awesome browser extensions</title>
      <link>https://seanmcp.com/articles/awesome-browser-extensions/</link>
      <description>&lt;p&gt;Extensions can slow down your browser, so I try to only add ones that are
necessary or super helpful. Here is a list of the extensions that make the cut,
grouped by category and listed alphabetically:&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;general-use&quot; tabindex=&quot;-1&quot;&gt;General use&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/awesome-browser-extensions/#general-use&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “General use”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/disable-automatic-gain-co/clpapnmmlmecieknddelobgikompchkk&quot;&gt;Disable automatic gain control&lt;/a&gt;:
I&#39;ve written
&lt;a href=&quot;https://seanmcp.com/articles/awesome-browser-extensions/articles/prevent-chrome-from-adjusting-audio-input-levels-on-mac/&quot;&gt;an article about this extension already&lt;/a&gt;;
it prevents Chrome from automatically adjusting the gain for your audio input.
I couldn&#39;t use Meet on Chrome without this extension!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm&quot;&gt;uBlock Origin&lt;/a&gt;:
Simple and effective ad blocking. &lt;strong&gt;Add this on every grandparent&#39;s
computer!&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;developers&quot; tabindex=&quot;-1&quot;&gt;Developers&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/awesome-browser-extensions/#developers&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Developers”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd&quot;&gt;axe DevTools&lt;/a&gt;:
Adds an accessibility audit panel to the developer tools.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/monaco-markdown-editor-fo/mmpbdjdnmhgkpligeniippcgfmkgkpnf&quot;&gt;Markdown Editor for GitHub&lt;/a&gt;:
Converts GitHub&#39;s default &lt;code&gt;textarea&lt;/code&gt; into a full-featured Monaco editor. This
means you can use your favorite VS-Code keyboard shortcuts when editing issue
descriptions and PR comments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This list will grow over time, so feel free to
&lt;a href=&quot;mailto:sean@seanmcp.com?subject=Suggesting%20an%20extension&quot;&gt;email suggestions&lt;/a&gt;
and check back later. Happy extending!&lt;/p&gt;
</description>
      <pubDate>Mon, 31 Oct 2022 13:11:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/awesome-browser-extensions/</guid>
    </item>
    <item>
      <title>Using dynamic routes to organize blog posts in Astro</title>
      <link>https://seanmcp.com/articles/using-dynamic-routes-to-organize-blog-posts-in-astro/</link>
      <description>&lt;p&gt;If you create a new Astro project with the installer, it will organize blog
posts as markdown files in a &lt;code&gt;src/pages/blog/&lt;/code&gt; directory. Each post will have
some frontmatter, including a &lt;code&gt;layout&lt;/code&gt; field to set the frame in which the
content will render.&lt;/p&gt;
&lt;p&gt;Astro will create a new page for every markdown file in the &lt;code&gt;src/pages/&lt;/code&gt;
directory, so adding a new post is as simple as a creating a new markdown file
in the &lt;code&gt;blog/&lt;/code&gt; subdirectory.&lt;/p&gt;
&lt;p&gt;When you want to render blog content on another page, &lt;em&gt;e.g.&lt;/em&gt; a homepage with the
last three posts, then you need to rely on two Astro APIs:
&lt;a href=&quot;https://docs.astro.build/en/guides/markdown-content/#compiledcontent&quot;&gt;&lt;code&gt;compiledContent&lt;/code&gt;&lt;/a&gt;
and/or
&lt;a href=&quot;https://docs.astro.build/en/guides/markdown-content/#content&quot;&gt;the &lt;code&gt;Content&lt;/code&gt; component&lt;/a&gt;.
These will give you the Astro-rendered content for a post that you can then add
to another page.&lt;/p&gt;
&lt;p&gt;There are two issues that I encountered using these APIs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;MDX does not support &lt;code&gt;compiledContent&lt;/code&gt;, so you can either omit &lt;code&gt;.mdx&lt;/code&gt; content
or create your own workaround with
&lt;a href=&quot;https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins&quot;&gt;rehype plugins&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;Content&lt;/code&gt; component for a post &lt;strong&gt;includes the markup for the layout&lt;/strong&gt;, so
&amp;quot;embedding&amp;quot; it in another page results in a strange iframe-esque page within
a page.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you just want to render the content of md/mdx files, there doesn&#39;t seem to be
a workable solution with the current setup. But with a little refactor, you can
have your cake and eat it too!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;a-new-organization-system&quot; tabindex=&quot;-1&quot;&gt;A new organization system&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/using-dynamic-routes-to-organize-blog-posts-in-astro/#a-new-organization-system&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “A new organization system”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Rather than putting all of your content somewhere in the &lt;code&gt;src/pages/&lt;/code&gt;, instead
let&#39;s create another directory at the same level as &lt;code&gt;src/&lt;/code&gt; called &lt;code&gt;content/&lt;/code&gt;.
This is where we will put all of our blog posts, maybe in a &lt;code&gt;blog/&lt;/code&gt;
subdirectory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;content/
    blog/
        first-post.md
        second-post.md
        third-post.md
src/
astro.config.mjs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we&#39;ll create a dynamic route for all blog posts in the &lt;code&gt;src/pages/blog/&lt;/code&gt;
directory. This file will gather all of the posts from your new &lt;code&gt;content/&lt;/code&gt;
directory create static paths for each:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;---
// src/pages/blog/[slug].astro

export function getStaticPaths() {
  const content = Astro.fetchContent(&quot;../../../content/blog/*.{md,mdx}&quot;);
  return content.map((item) =&gt; ({
    params: { slug: item.url.split(&quot;/&quot;).pop() },
    props: {
      ...item,
      // Any additional props
    },
  }));
}
---

&lt;!-- Render your post --&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Astro will call
&lt;a href=&quot;https://docs.astro.build/en/core-concepts/routing/#static-ssg-mode&quot;&gt;the &lt;code&gt;getStaticPaths&lt;/code&gt; function&lt;/a&gt;
and create a page for each item in the returned array with the given params.
We&#39;ve added the &lt;code&gt;item&lt;/code&gt; as props for the page, so we can access
&lt;a href=&quot;https://docs.astro.build/en/guides/markdown-content/#markdown-layout-props&quot;&gt;all of the data for each post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, we can remove the &lt;code&gt;layout:&lt;/code&gt; frontmatter from all of our posts in
&lt;code&gt;content/blog/&lt;/code&gt; and set the markup in our new dynamic route:&lt;/p&gt;
&lt;pre class=&quot;language-astro&quot;&gt;&lt;code class=&quot;language-astro&quot;&gt;---
// src/pages/blog/[slug].astro

export function getStaticPaths() {
  const content = Astro.fetchContent(&quot;../../../content/blog/*.{md,mdx}&quot;);
  return content.map((item) =&gt; ({
    params: { slug: item.url.split(&quot;/&quot;).pop() },
    props: {
      ...item,
      // Any additional props
    },
  }));
}

const {
  Content,
  frontmatter: { title },
} = Astro.props;
---

&lt;h1&gt;{title}&lt;/h1&gt;
&lt;Content&gt;&lt;/Content&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;call-out type=&quot;info&quot;&gt;
&lt;p&gt;Make sure to include post content in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; element too, and add encoding
to ensure that it renders correctly.&lt;/p&gt;
&lt;/call-out&gt;
&lt;p&gt;With all of that in place, you are now able to render markdown or MDX blog post
content anywhere on your site with Astro&#39;s &lt;code&gt;Content&lt;/code&gt; component; we&#39;re doing it
right here in our &lt;code&gt;[slug].astro&lt;/code&gt; file!&lt;/p&gt;
&lt;p&gt;In addition to resolving the issue above, I think I like this approach better
because it keeps the content separated from the code, which feel like different
concerns. As of publishing, I use it to organize notes, which are individuals
bits of md/mdx content that are &lt;a href=&quot;https://seanmcp.com/notes&quot;&gt;rendered on the notes page&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;tl%3Bdr&quot; tabindex=&quot;-1&quot;&gt;tl;dr&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/using-dynamic-routes-to-organize-blog-posts-in-astro/#tl%3Bdr&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “tl;dr”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Astro&#39;s default setup for organizing blog posts works well for a one-to-one
relationship between content and pages. But if you want to have a many-to-one
relationship with markdown and MDX, a better aproach may be layout-less posts
with a dynamic route.&lt;/p&gt;
&lt;p&gt;I hope that helps! Happy blogging 🚀&lt;/p&gt;
</description>
      <pubDate>Sat, 29 Oct 2022 17:21:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/using-dynamic-routes-to-organize-blog-posts-in-astro/</guid>
    </item>
    <item>
      <title>Jest</title>
      <link>https://seanmcp.com/articles/jest/</link>
      <description>&lt;p&gt;Since 2017, I have only used Jest for JavaScript application testing. And while
&lt;a href=&quot;https://vitest.dev/&quot;&gt;Vitest does look exciting&lt;/a&gt;, I think that it&#39;s safe to say
that Jest will be around for a good while longer.&lt;/p&gt;
&lt;p&gt;Here are some of tips and tricks that I&#39;ve learned that make working with Jest a
little better. The headings are organized alphabetically for ease of reference.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;aliases&quot; tabindex=&quot;-1&quot;&gt;Aliases&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/jest/#aliases&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Aliases”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Jest&#39;s global &lt;code&gt;test&lt;/code&gt; method has an &lt;code&gt;it&lt;/code&gt; alias that you might find useful. There
is usually a standard in the codebase where I&#39;m working, but I&#39;ve found that
tests can read a little more naturally with the alias:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;When a user is logged in, ...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Logs an event on interaction&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;expect&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;expect&lt;/code&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/jest/#expect&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “expect”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;There are a lot of matcher functions that are good to know, so I&#39;ll only list a
few here.&lt;/p&gt;
&lt;p&gt;One of the most useful matchers (and hardest to remember) is
&lt;code&gt;expect.objectContaining()&lt;/code&gt;. This allows you to assert that certain
properties/values are present on the object without needing to mock all of them.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockFn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  expect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;objectContaining&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another handy matcher is &lt;code&gt;not()&lt;/code&gt;, which gives you a simple way to negate any
matcher:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sum&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; readableTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;not&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I do recommend skimming the
&lt;a href=&quot;https://jestjs.io/docs/expect&quot;&gt;Jest docs for &lt;code&gt;expect&lt;/code&gt;&lt;/a&gt; occasionally to pick up
some new matcher that might help in your next test.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;flags&quot; tabindex=&quot;-1&quot;&gt;Flags&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/jest/#flags&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Flags”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The Jest CLI has a number of flags that can be used to change the way that Jest
runs. Here are some of the ones that I find most helpful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--bail/-b&lt;/code&gt;: Exits the test suite after a given number of failures (default 1)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--changedSince&lt;/code&gt;: Only run tests related to files changed since a given point.
I like to use this with the target branch as a quick check for regressions. -﻿
&lt;code&gt;--findRelatedTests&lt;/code&gt;: Runs tests related to changed files. Works well in a
pre-commit hook.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--watch&lt;/code&gt;: Run tests in watch mode. Great when running a small set of tests,
but maybe omit if you&#39;re running the whole suite.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;selective-runs&quot; tabindex=&quot;-1&quot;&gt;Selective runs&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/jest/#selective-runs&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Selective runs”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;When working in a large test file, it&#39;s nice to run only the cases that you care
about. Sometimes that means selecting a specific test or block, and other times
that means skipping anything that isn&#39;t necessary at the moment.&lt;/p&gt;
&lt;p&gt;To just run a specific test, you can use the &lt;code&gt;only()&lt;/code&gt; method on the global
&lt;code&gt;describe&lt;/code&gt;/&lt;code&gt;test&lt;/code&gt; methods. This will ensure that only that code is run:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;This test will run&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;This test will not&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To omit a test from the run, you can similarly use the &lt;code&gt;skip()&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;This test will run&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;skip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;This test will not&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a smaller change to skip tests, you can add an &lt;code&gt;x&lt;/code&gt; to the front of for the
same behavior:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;This test will run&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;xtest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;This test will not&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&#39;re going to use this, I&#39;d recommend
&lt;a href=&quot;https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/no-disabled-tests.md&quot;&gt;a linter rule to prevent you from committing skipped tests&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Thu, 06 Oct 2022 15:58:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/jest/</guid>
    </item>
    <item>
      <title>How to use StackBlitz with Firefox</title>
      <link>https://seanmcp.com/articles/use-stackblitz-with-firefox/</link>
      <description>&lt;p&gt;StackBlitz is a great tool for rapidly prototyping web applications. In recent
weeks, I has been my go-to tool for testing out new web technologies
(&lt;a href=&quot;https://seanmcp.com/notes/42/&quot;&gt;CodeSandbox&#39;s loss&lt;/a&gt;). However, when you try to use StackBlitz with
Firefox, the preview window gives the following error message:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/stackblitz-firefox-error.png&quot; alt=&quot;Error message reads: Enable Third-Party Cookies. Looks like your browser is blocking our Service Worker. To see this web page, please allow third-party cookies for this site.&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enable Third-Party Cookies Looks like your browser is blocking our Service
Worker. To see this web page,
&lt;a href=&quot;https://developer.stackblitz.com/docs/platform/third-party-blocker/&quot;&gt;please allow third-party cookies for this site&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you follow the link, it leads you to a guide for enabling the feature for
Chrome – a great addition to the error message but not helpful for Firefox
users.&lt;/p&gt;
&lt;p&gt;To enable the StackBlitz preview pane in Firefox, select the shield icon in the
URL bar and turn &amp;quot;Enhanced tracking protections&amp;quot; off for this site:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/stackblitz-firefox-setting.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once that setting is disabled, Firefox will prompt you to reload the page. Once
you do that, you should see the shield icon with a line through it to indicate
that Firefox is providing no additional protections:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/stackblitz-firefox-off.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;But more excitingly, the preview pane is now working! With that setting
configured, you should not be able to use StackBlitz&#39;s features in Firefox.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/stackblitz-firefox-working.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Happy blitzing!&lt;/p&gt;
</description>
      <pubDate>Tue, 23 Aug 2022 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/use-stackblitz-with-firefox/</guid>
    </item>
    <item>
      <title>How to replace Math.random with crypto in JavaScript</title>
      <link>https://seanmcp.com/articles/replace-math-random-with-crypto-in-javascript/</link>
      <description>&lt;p&gt;JavaScript has a method for generating random numbers from 0 to less than 1:
&lt;code&gt;Math.random()&lt;/code&gt;. If you&#39;ve ever been working on an app that selects a random
item from a list, chances are that you&#39;ve done something like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; randomItem &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will probably work for 99% of the use cases of a random number. However,
numbers generated from &lt;code&gt;Math.random&lt;/code&gt; are &lt;strong&gt;not&lt;/strong&gt; cryptographically secure. That
means that the &amp;quot;random&amp;quot; values are guessable by a computer and therefore not
suitable for use in cryptography.&lt;/p&gt;
&lt;p&gt;Thankfully, we have other methods of generating random numbers in the browser:
&lt;code&gt;crypto&lt;/code&gt;.
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues&quot;&gt;This global object has a &lt;code&gt;getRandomValues&lt;/code&gt; method&lt;/a&gt;
that we can use to recreate the functionality above. The method needs to be
called with an typed array, so we&#39;ll create one with the &lt;code&gt;Uint8Array&lt;/code&gt;
constructor with a length of 1:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; typedArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we pass this to &lt;code&gt;getRandomValues&lt;/code&gt; and select the first (and only) item from
the returned array.&lt;/p&gt;
&lt;!-- ```js/1 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; typedArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; randomValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; crypto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRandomValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;typedArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// E.g. 122&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we used an &lt;code&gt;Uint8Array&lt;/code&gt;, all of the numbers generated will from 0 to 255.
To convert that into the same float returned from &lt;code&gt;Math.random&lt;/code&gt;, we need to
divide the value by the total number of possible numbers: 256 or 2&lt;sup&gt;8&lt;/sup&gt;.&lt;/p&gt;
&lt;!-- ```js/2 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; typedArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; randomValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; crypto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRandomValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;typedArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; randomFloat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; randomValue &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// E.g. 0.4765625&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With these steps in place, we can create a function that is a drop-in
replacement for &lt;code&gt;Math.random&lt;/code&gt; called &lt;code&gt;cryptoRandom&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cryptoRandom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; typedArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; randomValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; crypto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRandomValues&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;typedArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; randomFloat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; randomValue &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; randomFloat&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few things to note:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;You&#39;ll (probably) never need this&lt;/strong&gt;. Reach for &lt;code&gt;Math.random&lt;/code&gt; unless you
have a very specific reason for cryptographic security.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The floats from this method are shorter&lt;/strong&gt;. &lt;code&gt;Math.random&lt;/code&gt; pretty
consistently returns floats that are 10+ decimal places long. If you are
depending on a long tail of numbers, then consider switching to &lt;code&gt;Uint32Array&lt;/code&gt;
and dividing by &lt;code&gt;Math.pow(2, 32)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I&#39;m not a security expert&lt;/strong&gt;. All of the information in this article was
from a quick Google search; make sure to consult people who know what they&#39;re
talking about before copying and pasting code from a random website.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I hope that helps and as always: let me know if you have any corrections to the
article.&lt;/p&gt;
&lt;p&gt;Happy randomizing!&lt;/p&gt;
</description>
      <pubDate>Mon, 18 Jul 2022 18:15:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/replace-math-random-with-crypto-in-javascript/</guid>
    </item>
    <item>
      <title>Use multiple Chrome Profiles when debugging</title>
      <link>https://seanmcp.com/articles/use-multiple-chrome-profiles-when-debugging/</link>
      <description>&lt;p&gt;Awhile back, I read about using separate Chrome profiles&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/use-multiple-chrome-profiles-when-debugging/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; for debugging. The
idea is to have specific environments that are specially configured to debug
different kinds of issues.&lt;/p&gt;
&lt;p&gt;While the article mentioned many different profiles for different users and
scenarios, I’ve found myself settling on three: my main profile, the guest
profile, and a DevTools profile.&lt;/p&gt;
&lt;p&gt;The main profile is where I am signed into Google with my personal or work email
address. If you use Google Chrome regularly and have a Google account, you
probably have a profile setup already. This is where I do most of my development
and debugging work. I have a selection of extensions installed and a few
resources like bookmarks and snippets to help my workflow. The first step when
debugging is to use my current setup – if I can get things reproducing here,
great! But if I have to alter settings or clear data, then I reach for something
else.&lt;/p&gt;
&lt;p&gt;The next option is the default Guest profile in Chrome. When switching to a
guest profile, you lose the session and any information stored in the browser.
It&#39;s a clean slate. This is helpful when you want to reproduce the bug in a
particular scenario but don’t want to logout or toggle feature flags on your
main profile. Guest profiles have full access to the browser’s DevTools but do
not support extensions. For that, I have a third option.&lt;/p&gt;
&lt;p&gt;Finally, I have a profile specifically for DevTool extensions. Here I have the
React DevTools installed, and any additional else that would be helpful when
debugging. If I know that I am investigating a React issue, I will switch over
to this profile and then explore the tree with the Components panel or run tests
in the Profiler. Any created profile will save site data, so I make a point of
frequently resetting everything to ensure a clean environment for reproducing
bugs.&lt;/p&gt;
&lt;p&gt;With these three profiles, I find that I&#39;m better able to identify and fix
issues that I encounter when developing. Give it a try and let me know how it
works for you.&lt;/p&gt;
&lt;p&gt;Happy debugging!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Read Vitaly Friedman’s
&lt;a href=&quot;https://www.smashingmagazine.com/2021/02/useful-chrome-firefox-devtools-tips-shortcuts/&quot;&gt;&lt;em&gt;DevTools Debugging Tips And Shortcuts&lt;/em&gt;&lt;/a&gt; &lt;a href=&quot;https://seanmcp.com/articles/use-multiple-chrome-profiles-when-debugging/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 06 Jun 2022 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/use-multiple-chrome-profiles-when-debugging/</guid>
    </item>
    <item>
      <title>When to use React&#39;s memo HOC</title>
      <link>https://seanmcp.com/articles/when-to-use-reacts-memo-hoc/</link>
      <description>&lt;p&gt;When React wants to render a component, it renders all of the components in the
tree from that point. So if you have a parent component with two child
components, a re-render (↻) of the parent will include re-rendering both
children.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Parent ↻
├── ChildA ↻
└── ChildB ↻
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since data typically flows down the tree, this is the behavior that you probably
want for the UI to reflect the current state of the application.&lt;/p&gt;
&lt;p&gt;However, there may be instances when you do not want a component to re-render
when its ancestor re-renders. Let&#39;s imagine a similar scenario with two
children. One of the components is presentational while the other has a deep
tree of its own.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Parent
├── BasicChild
└── ComplexChild
    ├── GrandChildA
    └── GrandChildB
        └── GreatGrandChild
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just like before, any changes (✴) to the parent will result in re-rendering all
if its children – including the complex subtree. Depending on the depth of the
tree or the complexity of the render, this could be a time-consuming render
cycle.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Parent ✴↻
├── BasicChild ↻
└── ComplexChild ↻
    ├── GrandChildA ↻
    └── GrandChildB ↻
        └── GreatGrandChild ↻
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want to prevent &lt;code&gt;ComplexChild&lt;/code&gt; from re-rendering unnecessarily to improve the
performance of our application.&lt;/p&gt;
&lt;p&gt;Thankfully, React has some features to accomplish this.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;class-components&quot; tabindex=&quot;-1&quot;&gt;Class components&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/when-to-use-reacts-memo-hoc/#class-components&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Class components”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Class components have
&lt;a href=&quot;https://reactjs.org/docs/react-component.html#shouldcomponentupdate&quot;&gt;a &lt;code&gt;shouldComponentUpdate&lt;/code&gt; lifecycle method&lt;/a&gt;
that allow you to determine whether a component should re-render based on props
and state.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PreventRerender&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;shouldComponentUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;nextProps&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nextState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; nextProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactpurecomponent&quot;&gt;&lt;code&gt;PureComponent&lt;/code&gt; goes one step further&lt;/a&gt;
by implementing &lt;code&gt;shouldComponentUpdate&lt;/code&gt; with a shallow prop and state
comparison. When you component extends &lt;code&gt;PureComponent&lt;/code&gt;, it will only re-render
if its props or state have changed.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PreventRerender&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PureComponent&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;function-components&quot; tabindex=&quot;-1&quot;&gt;Function components&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/when-to-use-reacts-memo-hoc/#function-components&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Function components”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;For modern function components with no lifecycle methods, we need a different
solution.
&lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactmemo&quot;&gt;React exports a &lt;code&gt;memo&lt;/code&gt; higher-order component&lt;/a&gt;
(HOC) that takes a function component and returns a wrapped component that will
only re-render if a shallow comparison of props indicates a change.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; PreventRerender &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PreventRerender&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For more customization, you can pass an optional compare function to
&lt;code&gt;React.memo&lt;/code&gt; as a second argument that determines whether to render based on
previous and next props.&lt;/p&gt;
&lt;p&gt;Any of the strategies above to prevent unnecessary re-renders come at a small
cost, so make sure to implement them only when necessary. You can use the React
DevTools&#39; Profiler panel to determine which areas of the React tree are good
candidates for performance improvements.&lt;/p&gt;
&lt;p&gt;In our example above, we could wrap our complex component with &lt;code&gt;React.memo&lt;/code&gt; in
order to prevent re-rendering when the props are unchanged:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ComplexChild&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We would not need to do anything to the basic child component, as any
memoization or lifecycle checks would probably be more expensive than the cost
of re-rendering.&lt;/p&gt;
&lt;p&gt;With that change in place, a change within the parent component would only
result in re-renders for &lt;code&gt;Parent&lt;/code&gt; and &lt;code&gt;BasicChild&lt;/code&gt; – the expensive tree in
&lt;code&gt;ComplexChild&lt;/code&gt; would not change.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Parent ✴↻
├── BasicChild ↻
└── ComplexChild
    ├── GrandChildA
    └── GrandChildB
        └── GreatGrandChild
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hope that helps explain when and how to use React&#39;s &lt;code&gt;memo&lt;/code&gt; HOC.&lt;/p&gt;
&lt;p&gt;Happy memoizing!&lt;/p&gt;
</description>
      <pubDate>Thu, 28 Apr 2022 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/when-to-use-reacts-memo-hoc/</guid>
    </item>
    <item>
      <title>Calculate the sum of everything up to a given number</title>
      <link>https://seanmcp.com/articles/calculate-the-sum-of-everything-up-to-a-given-number/</link>
      <description>&lt;p&gt;My wife showed me a Tik Tok series where someone was decluttering their life by
getting rid of an increasing amount of items every day for 30 days. That&#39;s kind
of hard to type out, but the idea was getting rid of one thing on day 1, then
two things on day 2, &lt;em&gt;etc.&lt;/em&gt; until tossing thirty things on day 30.&lt;/p&gt;
&lt;p&gt;It was late a night, and we both struggled with the math of determining how many
items this person would give away by the end of the experiment&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/calculate-the-sum-of-everything-up-to-a-given-number/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. Being an
engineer, I set out the next day to create a little tool to calculate that for
you.&lt;/p&gt;
&lt;p&gt;Type in the number of steps (in our case 30 for thirty days), and select
&amp;quot;Calculate&amp;quot; to see the sum:&lt;/p&gt;
&lt;cumulative-sum&gt;
&lt;p&gt;Try this interactive on &lt;a href=&quot;https://seanmcp.com&quot;&gt;seanmcp.com&lt;/a&gt;&lt;/p&gt;
&lt;/cumulative-sum&gt;
&lt;p&gt;I remember seeing something similar when I was in college and folks would try to
raise support to go on a mission trip. They would have a board with every number
from 1 to 100 (or so) and try to find people who are willing to donate that
amount. With this calculator, you should be able to figure out how long your
support board needs to be with some guess and check.&lt;/p&gt;
&lt;p&gt;Hopefully this helps someone else.&lt;/p&gt;
&lt;p&gt;Happy counting!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Spoiler: It&#39;s 465 items &lt;a href=&quot;https://seanmcp.com/articles/calculate-the-sum-of-everything-up-to-a-given-number/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Sat, 23 Apr 2022 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/calculate-the-sum-of-everything-up-to-a-given-number/</guid>
    </item>
    <item>
      <title>English words by consonant-vowel pattern</title>
      <link>https://seanmcp.com/articles/english-words-by-consonant-vowel-pattern/</link>
      <description>&lt;p&gt;When teaching people (or computers) to read, it&#39;s useful to group similar words
into categories. One such grouping is by consonant-vowel patterns, which
represent words by the letters that they contain.&lt;/p&gt;
&lt;p&gt;With consonant-vowel patterns, we can put words like &amp;quot;bun&amp;quot;, &amp;quot;cat&amp;quot;, and &amp;quot;dip&amp;quot;
into one bucket as &amp;quot;cvc&amp;quot; words; they are all made up of a consonant, followed by
a vowel, and ending in a consonant.&lt;/p&gt;
&lt;p&gt;I put together
&lt;a href=&quot;https://github.com/SeanMcP/reading/tree/master/consonant-vowel-patterns&quot;&gt;a list of all English words sorted by their consonant-vowel pairs&lt;/a&gt;.
However, that is a long list to search through and I thought it might be nice to
have a tool to look up shorter words by their consonant-vowel pattern.&lt;/p&gt;
&lt;consonant-vowel-patterns&gt;
    &lt;form&gt;
        &lt;label&gt;
            &lt;b&gt;Pattern&lt;/b&gt;
            &lt;select name=&quot;pattern&quot;&gt;&lt;/select&gt;
        &lt;/label&gt;
        &lt;button&gt;Search&lt;/button&gt;
    &lt;/form&gt;
    &lt;output&gt;&lt;/output&gt;
&lt;/consonant-vowel-patterns&gt;
&lt;p&gt;The word list isn&#39;t perfect, but hopefully it will give you all of the data that
you need for your use case! Let me know if you have any suggestions or run into
any issues.&lt;/p&gt;
&lt;p&gt;Happy reading!&lt;/p&gt;
</description>
      <pubDate>Thu, 03 Mar 2022 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/english-words-by-consonant-vowel-pattern/</guid>
    </item>
    <item>
      <title>Add a custom emulated device in Chrome</title>
      <link>https://seanmcp.com/articles/add-a-custom-emulated-device-in-chrome/</link>
      <description>&lt;p&gt;Google Chrome provides a feature in the dev tools to emulate a device within the
desktop browser. This is really helpful to get a quick preview of what a webpage
will look like on different types and sizes of devices.&lt;/p&gt;
&lt;p&gt;You can also add a custom emulated device that meets the specifications of your
users. For example, if you work on a product that is primarily used by school
students on Chromebooks, then it would be useful to have an emulated device that
you could easily select.&lt;/p&gt;
&lt;p&gt;To add a custom emulated device in Chrome, first
&lt;a href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools&quot;&gt;open the dev tools with your favorite method&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/custom-emulated-device-1.png&quot; alt=&quot;step 1: open the dev tools&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then select toggle the device toolbar by clicking the phone/tablet icon or using
the shortcut &lt;kbd&gt;ctrl&lt;/kbd&gt;/&lt;kbd&gt;cmd&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;m&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/custom-emulated-device-2.png&quot; alt=&quot;step 2: open the device toolbar&quot;&gt;&lt;/p&gt;
&lt;p&gt;Open the dropdown to see all of the default devices available in Chrome. To add
a new one, select &amp;quot;Edit&amp;quot; at the bottom of the list.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/custom-emulated-device-3.png&quot; alt=&quot;step 3: select to edit devices&quot;&gt;&lt;/p&gt;
&lt;p&gt;This should review a new dev-tools panel. Here you can select from a greater
list of default devices. To add a new device, select &amp;quot;Add custom device...&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/custom-emulated-device-4.png&quot; alt=&quot;step 4: select &amp;quot;add custom device&amp;quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Next, input the dimensions for your custom device. I have two Chromebooks with
two different window dimensions: 1366x649 and 1300x605. I&#39;d rather test again
the more extreme device, but you do whatever makes sense for you.&lt;/p&gt;
&lt;p&gt;Make sure to select the correct user agent type! For a Chromebook, I&#39;m going
with &amp;quot;Desktop (touch)&amp;quot;.&lt;/p&gt;
&lt;p&gt;When you are done, select &amp;quot;Add&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/custom-emulated-device-5.png&quot; alt=&quot;step 5: input device dimensions&quot;&gt;&lt;/p&gt;
&lt;p&gt;With your custom emulated device added, you can now selected it from the
responsive device dropdown menu back on the far left.&lt;/p&gt;
&lt;p&gt;The screenshot below illustrates just how different the real estate is for a
Chromebook user compared to someone on a full-sized laptop or desktop:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/custom-emulated-device-6.png&quot; alt=&quot;step 6: use your custom device&quot;&gt;&lt;/p&gt;
&lt;p&gt;With custom emulated devices, we can test to make sure that our webpages and
applications will work well for all of our users.&lt;/p&gt;
&lt;p&gt;Happy customizing!&lt;/p&gt;
</description>
      <pubDate>Sat, 05 Feb 2022 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/add-a-custom-emulated-device-in-chrome/</guid>
    </item>
    <item>
      <title>Upgrading an Eleventy site to 1.0.0</title>
      <link>https://seanmcp.com/articles/upgrading-an-eleventy-site-to-1-0-0/</link>
      <description>&lt;p&gt;I initially published a &lt;a href=&quot;https://seanmcp.com/notes&quot;&gt;note&lt;/a&gt; about how easy it was to upgrade to
Eleventy &lt;code&gt;1.0.0&lt;/code&gt;, but I hit a snag which warrants a quick article. Here are the
two steps that I needed to complete to update this website to the latest version
of Eleventy.&lt;/p&gt;
&lt;p&gt;First, update &lt;code&gt;@11ty/eleventy&lt;/code&gt; with the following command:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; i &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; @11ty/eleventy@latest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After updating that, both the &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; scripts for the site worked as
expected.
&lt;a href=&quot;https://github.com/11ty/eleventy/releases/tag/v1.0.0&quot;&gt;There are breaking changes to be aware of&lt;/a&gt;,
so your mileage may vary.&lt;/p&gt;
&lt;p&gt;I took the time to update some other dependencies and pushed the changes to
GitHub. I have the repo connected to Netlify for CI/CD, which usually works
without a hitch. Today, however, I noticed that the build failed with the
following log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;10:03:16 AM: $ eleventy
10:03:16 AM: Eleventy requires Node 12. You will need to upgrade Node to use Eleventy!
10:03:16 AM: ​
10:03:16 AM: ────────────────────────────────────────────────────────────────
10:03:16 AM:   &amp;quot;build.command&amp;quot; failed
10:03:16 AM: ────────────────────────────────────────────────────────────────
10:03:16 AM: ​
10:03:16 AM:   Error message
10:03:16 AM:   Command failed with exit code 1: eleventy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There weren&#39;t any build configurations in Netlify for Node.js version, but a
quick search led me to
&lt;a href=&quot;https://docs.netlify.com/configure-builds/manage-dependencies/#node-js-and-javascript&quot;&gt;this guide on managing build dependencies&lt;/a&gt;.
Good documentation; another reason to use Netlify!&lt;/p&gt;
&lt;p&gt;I added an environment variable for &lt;code&gt;NODE_VERSION&lt;/code&gt; and set it to the current
Node.js LTS (&lt;code&gt;16.13.2&lt;/code&gt; as of writing), and the build was successful.&lt;/p&gt;
&lt;p&gt;Regardless of your setup, just make sure that you are using Node.js version &lt;code&gt;12&lt;/code&gt;
or later and you should be good to go. &lt;e-moji&gt;🚀&lt;/e-moji&gt;&lt;/p&gt;
&lt;p&gt;Happy upgrading!&lt;/p&gt;
</description>
      <pubDate>Tue, 18 Jan 2022 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/upgrading-an-eleventy-site-to-1-0-0/</guid>
    </item>
    <item>
      <title>Make a web component</title>
      <link>https://seanmcp.com/articles/make-a-web-component/</link>
      <description>&lt;p&gt;To make a web component, you need to create a new class. You can extend an
existing component class if you want to preserve some semantic behavior, but
we&#39;ll go with the default &lt;code&gt;HTMLElement&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HelloWorld&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we need to add a &lt;code&gt;constructor&lt;/code&gt; method and call the &lt;code&gt;super&lt;/code&gt; function to
ensure that our component is initialized with all the necessary information:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HelloWorld&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need a DOM to build on. Web components use
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM&quot;&gt;a shadow DOM&lt;/a&gt;,
which we&#39;ll create by calling our class&#39;s &lt;code&gt;attachShadow&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HelloWorld&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shadow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachShadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;open&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With our shadow DOM declared, we can create a new element. Let&#39;s go with a span
element with the content &amp;quot;Hello world!&amp;quot; and append it to our shadow:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HelloWorld&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shadow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachShadow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;open&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; span &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;span&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    span&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    shadow&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;span&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last thing we need to do is define our custom web component with:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HelloWorld&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* Collapsed for brevity */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hello-world&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HelloWorld&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, references your new element in the HTML:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;hello-world&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;hello-world&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Congratulations, you just made your first web component!&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Fri, 14 Jan 2022 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/make-a-web-component/</guid>
    </item>
    <item>
      <title>Prevent Chrome from adjusting audio input levels on Mac</title>
      <link>https://seanmcp.com/articles/prevent-chrome-from-adjusting-audio-input-levels-on-mac/</link>
      <description>&lt;p&gt;Starting Fall of 2021, I noticed that my bluetooth headphones would periodically
mute me while I was speaking during video chats on Google Meet. I tried multiple
sets of bluetooth headphones, and they all had the same issue.&lt;/p&gt;
&lt;p&gt;I learned last week that macOS will automatically mute an audio input when the
input level is set to zero. While in meetings, I kept an eye on the level in
System Preferences &amp;gt; Sound &amp;gt; Input and noticed that it would decrease as I
spoke. As soon as the level reached zero, my headset would notify me that it had
been muted.&lt;/p&gt;
&lt;p&gt;There are no settings in Google Chrome (on in my case, the new Microsoft Edge)
nor Google Meet to disable those input level adjustments, and there is
&lt;a href=&quot;https://support.google.com/chrome/thread/7542181/chrome-is-auto-adjusting-the-microphone-level?hl=en&quot;&gt;an unanswered help question&lt;/a&gt;)
with a lot of folks experiencing the same issue.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://support.google.com/chrome/thread/7542181/chrome-is-auto-adjusting-the-microphone-level?hl=en&quot;&gt;One of the responders&lt;/a&gt;
came up with a solution:
&lt;a href=&quot;https://chrome.google.com/webstore/detail/disable-automatic-gain-co/clpapnmmlmecieknddelobgikompchkk&quot;&gt;a Chrome extension&lt;/a&gt;
that prevents certain domains from changing the input levels.&lt;/p&gt;
&lt;p&gt;After installing that from the Chrome Web Store, I navigated to Google Meet,
activated the extension, and gave it permissions on that domain. The page
refreshed, and the issue was resolved: no more adjusted input levels and no more
unwanted muting.&lt;/p&gt;
&lt;p&gt;It’s great that there are creative solutions like this available, h/t
&lt;a href=&quot;https://github.com/joeywatts&quot;&gt;Joey Watts&lt;/a&gt;, but its frustrating that issues like
this can go unresolved for so long on popular projects like Google Chrome.&lt;/p&gt;
&lt;p&gt;Happy resolving!&lt;/p&gt;
</description>
      <pubDate>Tue, 11 Jan 2022 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/prevent-chrome-from-adjusting-audio-input-levels-on-mac/</guid>
    </item>
    <item>
      <title>Helpful online tools for diagramming</title>
      <link>https://seanmcp.com/articles/helpful-online-tools-for-diagramming/</link>
      <description>&lt;p&gt;A good diagram can make a big difference when communicating a message. I often
turn to a diagramming tool when trying to explain a complex idea or organize my
thoughts when brainstorming. Thankfully, there a bunch of online tools to help
you make quality diagrams. Here are a few options for your to use:&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;excalidraw&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://excalidraw.com/&quot;&gt;Excalidraw&lt;/a&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/helpful-online-tools-for-diagramming/#excalidraw&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Excalidraw”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/excalidraw-example.png&quot; alt=&quot;Excalidraw example diagram&quot;&gt;&lt;/p&gt;
&lt;p&gt;Excalidraw makes it easy to create quick diagrams that look sketchy. It saves
your changes to local storage (which is super handy), and supports a backup
option to download/upload an illustration. There is a live collaboration feature
that I haven&#39;t tried, and some premium offerings with Excalidraw+.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;tl-draw&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://www.tldraw.com/&quot;&gt;TL Draw&lt;/a&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/helpful-online-tools-for-diagramming/#tl-draw&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “TL Draw”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/tldraw-example.png&quot; alt=&quot;TL Draw example diagram&quot;&gt;&lt;/p&gt;
&lt;p&gt;TL Draw has a similar feature set to Excalidraw but diagrams look a little more
neat and tidy. Depending on the style you are aiming for, this may be the better
option for you. The biggest difference is that your changes are not saved to
local storage; so make sure to backup your illustration!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;draw.io&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://draw.io&quot;&gt;Draw.io&lt;/a&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/helpful-online-tools-for-diagramming/#draw.io&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Draw.io”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/draw-io-example.png&quot; alt=&quot;Draw.io example diagram&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://Draw.io&quot;&gt;Draw.io&lt;/a&gt; makes creating diagrams and flowcharts easy and painless. It supports a
lot of different element options and seems to be a go-to option for diagramming
complex microservice systems. It has a desktop application and backs up to the
cloud. My only criticism is that the illustrations from &lt;a href=&quot;http://Draw.io&quot;&gt;Draw.io&lt;/a&gt; are not pretty;
it&#39;s definitely function over form.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;google-drawings&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://drive.google.com&quot;&gt;Google Drawings&lt;/a&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/helpful-online-tools-for-diagramming/#google-drawings&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Google Drawings”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/google-drawings-example.png&quot; alt=&quot;Google Drawings example diagram&quot;&gt;&lt;/p&gt;
&lt;p&gt;One of the forgotten tools of Google Drive, Drawings is an adequate option for
simple diagrams. If you or your organization are already using Google, it will
be the easiest option if not the most inspired.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you have any other suggestions to add to this list,
&lt;a href=&quot;https://seanmcp.com/articles/helpful-online-tools-for-diagramming/#comment-link&quot;&gt;please let me know&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy diagramming!&lt;/p&gt;
</description>
      <pubDate>Wed, 15 Dec 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/helpful-online-tools-for-diagramming/</guid>
    </item>
    <item>
      <title>What is a build.gradle file?</title>
      <link>https://seanmcp.com/articles/what-is-a-build-gradle-file/</link>
      <description>&lt;p&gt;When working on a React Native app, you will probably make some changes to the
&lt;code&gt;build.gradle&lt;/code&gt; file in your projects &lt;code&gt;android/&lt;/code&gt; directory. This file is the core
component of your build process and has all of the instructions necessary to
compile an Android app from source.&lt;/p&gt;
&lt;p&gt;Your &lt;code&gt;build.gradle&lt;/code&gt; file is read and executed by &lt;a href=&quot;https://gradle.org/&quot;&gt;Gradle&lt;/a&gt;,
an automation tool that is popular in Java development. Gradle&#39;s job is to
resolve the dependency tree of your application and run everything through the
Java compiler to generate code that can be run in the Java Virtual Machine
(JVM). All of that work is divided in to tasks that can be mixed and matched as
needed.&lt;/p&gt;
&lt;p&gt;The nearest equivalent in the world of web development might be
&lt;a href=&quot;https://gulpjs.com/&quot;&gt;Gulp, a composable task runner&lt;/a&gt;,, or perhaps
&lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack, a bundler&lt;/a&gt;. But &lt;code&gt;build.gradle&lt;/code&gt; also manages
dependencies, so mix a little bit of &lt;code&gt;package.json&lt;/code&gt; in there too. Essentially,
&lt;code&gt;build.gradle&lt;/code&gt; is the main configuration file for your Android project.&lt;/p&gt;
&lt;p&gt;When you look at
&lt;a href=&quot;https://github.com/facebook/react-native/blob/main/template/android/build.gradle&quot;&gt;a &lt;code&gt;build.gradle&lt;/code&gt; file&lt;/a&gt;
through the lens of a web developer, it looks like a bunch of nested objects
with a few method calls. However, that is completely wrong!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;build.gradle&lt;/code&gt; files are often written in
&lt;a href=&quot;https://groovy-lang.org/&quot;&gt;Groovy, which is its own Java-based programming language&lt;/a&gt;.
What looks like an object declaration in JavaScript is actually a function call
in Groovy. Let&#39;s take a look at the following block:&lt;/p&gt;
&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;repositories &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;google&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    maven &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; url &lt;span class=&quot;token string&quot;&gt;&#39;https://www.jitpack.io&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we are calling the &lt;code&gt;repositories&lt;/code&gt; function and passing a closure,
identified by the curly brackets &lt;code&gt;{}&lt;/code&gt;. Within that closure, we are calling more
functions: &lt;code&gt;google&lt;/code&gt; with no parameters, and &lt;code&gt;maven&lt;/code&gt; with another closure and
another function &lt;code&gt;url&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;m still working to wrap my head around closures, but the takeaway here is that
there is more going on that you might first assume.&lt;/p&gt;
&lt;p&gt;The best part about using a programming language for a build configuration file
is that you can add variables and functions as needed. Variables and functions
can be defined with the &lt;code&gt;def&lt;/code&gt; keyword customize the build process:&lt;/p&gt;
&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; version &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;1.2.3&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;customFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    println &lt;span class=&quot;token interpolation-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Building v&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;customFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last bit of information you should know about &lt;code&gt;build.gradle&lt;/code&gt; is that all of
the tasks are executed via a wrapper. This is the executable &lt;code&gt;gradlew&lt;/code&gt;
(Linux/Mac) or &lt;code&gt;gradlew.bat&lt;/code&gt; (Windows) file that is included in your project. By
running everything through the wrapper, you remove the need to have Gradle
installed on your computer.&lt;/p&gt;
&lt;p&gt;To start the build task, run the following in your terminal:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;./gradlew build&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hopefully that demystifies the &lt;code&gt;build.gradle&lt;/code&gt; file in your Android/React-Native
project a little bit. This is not yet my area of expertise, so
&lt;a href=&quot;https://seanmcp.com/articles/what-is-a-build-gradle-file/#comment-link&quot;&gt;please let me know&lt;/a&gt; if I need to make any corrections.&lt;/p&gt;
&lt;p&gt;Happy building!&lt;/p&gt;
</description>
      <pubDate>Thu, 04 Nov 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/what-is-a-build-gradle-file/</guid>
    </item>
    <item>
      <title>Three new games on Toollama</title>
      <link>https://seanmcp.com/articles/three-new-games-on-toollama/</link>
      <description>&lt;p&gt;I don&#39;t think I&#39;ve written about &lt;a href=&quot;http://Toollama.com&quot;&gt;Toollama.com&lt;/a&gt; yet on this site, so here&#39;s a
quick introduction. Toollama is a loose collection of education-focused
productivity tools and games. For the past year, it has been the home of all of
the little apps that I create for myself, teachers, or my kids.&lt;/p&gt;
&lt;p&gt;Over the past three weeks, I have created two new games and one new activity to
help children develop core computer skills:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🐢 &lt;a href=&quot;https://seanmcp.github.io/turtle-guide&quot;&gt;Turtle Guide&lt;/a&gt;: Use the arrow keys
to help a little turtle find his way home&lt;/li&gt;
&lt;li&gt;🐷 &lt;a href=&quot;https://seanmcp.github.io/paint-pig&quot;&gt;Paint Pig&lt;/a&gt;: Use the arrow keys to
help Pig paint a picture&lt;/li&gt;
&lt;li&gt;🔦 &lt;a href=&quot;https://seanmcp.github.io/spotlight&quot;&gt;Spotlight&lt;/a&gt;: Use the mouse/trackpad to
reveal animals hidden in color nature scenes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From a technical perspective, these are all vanilla JS, CSS, and HTML served
from GitHub Pages. I&#39;ve found that solving problems with simple tools has been a
relaxing change of pace from the complex environments of work. As always, the
code is open source on GitHub:
&lt;a href=&quot;https://github.com/seanmcp/turtle-guide&quot;&gt;&lt;code&gt;turtle-guide&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;https://github.com/seanmcp/paint-pig&quot;&gt;&lt;code&gt;paint-pig&lt;/code&gt;&lt;/a&gt;, and
&lt;a href=&quot;https://github.com/seanmcp/spotlight&quot;&gt;&lt;code&gt;spotlight&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These additions bring the grand total on Toollama up to 13 apps!
&lt;a href=&quot;https://seanmcp.com/tools&quot;&gt;Check it out, if you haven&#39;t already&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy learning!&lt;/p&gt;
</description>
      <pubDate>Wed, 27 Oct 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/three-new-games-on-toollama/</guid>
    </item>
    <item>
      <title>React Native Glossary</title>
      <link>https://seanmcp.com/articles/react-native-glossary/</link>
      <description>&lt;p&gt;Building applications with React Native requires a high-level understanding of
mobile development on Android and iOS devices in addition to React and React
Native fundamentals. This glossary of terms will serve as a helpful reference
when working across these environments.&lt;/p&gt;
&lt;hr&gt;
&lt;!--
TERMS TO ADD:
- JDK
- JRE
--&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;aab&quot; tabindex=&quot;-1&quot;&gt;AAB&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/react-native-glossary/#aab&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “AAB”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Android App Bundles (AABs) are a new format for publishing applications on
Android. AABs can contain multiple APKs. Since August 2021, Google Play requires
AABs for new apps.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.android.com/guide/app-bundle&quot;&gt;About Android App Bundles (Android)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;apk&quot; tabindex=&quot;-1&quot;&gt;APK&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/react-native-glossary/#apk&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “APK”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Android Package Kits (APKs) are an older format for publishing applications on
Android.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;build.gradle&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;build.gradle&lt;/code&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/react-native-glossary/#build.gradle&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “build.gradle”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A &lt;code&gt;build.gradle&lt;/code&gt; file contains all of the information for Gradle to compile
Android apps, including dependency resolutions and tasks to process the source.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://seanmcp.com/articles/what-is-a-build-gradle-file&quot;&gt;&lt;em&gt;What is a &lt;code&gt;build.gradle&lt;/code&gt; file?&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;gradle&quot; tabindex=&quot;-1&quot;&gt;Gradle&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/react-native-glossary/#gradle&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Gradle”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Gradle is an automated build tool that is used to compile Android apps from
source code. It is configured in &lt;code&gt;build.gradle&lt;/code&gt; files and run through a wrapper:
&lt;code&gt;gradlew&lt;/code&gt;/&lt;code&gt;gradlew.bat&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gradle.org/&quot;&gt;Gradle Build Tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=-dtcEMLNmn0&quot;&gt;Gradle tutorial for complete beginners (YouTube)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;hermes&quot; tabindex=&quot;-1&quot;&gt;Hermes&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/react-native-glossary/#hermes&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Hermes”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Hermes is a mobile-optimized JavaScript engine that is included in React Native
builds for Android and iOS.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://reactnative.dev/docs/hermes&quot;&gt;Using Hermes (React Native)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://seanmcp.com/articles/what-is-hermes-react-native/&quot;&gt;What is Hermes in React Native?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;info.plist&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;Info.plist&lt;/code&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/react-native-glossary/#info.plist&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Info.plist”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The information property list or &lt;code&gt;Info.plist&lt;/code&gt; is an XML file that contains all
of the configuration data for your application. You can update these values
directly or through the Xcode UI.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html&quot;&gt;About Info.plist Keys and Values (Apple)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;javascriptcore%2Fjscore&quot; tabindex=&quot;-1&quot;&gt;JavaScriptCore/JSCore&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/react-native-glossary/#javascriptcore%2Fjscore&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “JavaScriptCore/JSCore”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;JavaScript Core or JSCore is a JavaScript engine that is included on iOS
devices. It was included in Android builds to run JS code by React Native
versions prior to &lt;code&gt;0.60&lt;/code&gt;. It has since been replaced with &lt;a href=&quot;https://seanmcp.com/articles/react-native-glossary/#hermes&quot;&gt;Hermes&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/javascriptcore&quot;&gt;JavaScriptCore (Apple)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!--
## JRE

A Java Runtime Environment (JRE) is the code required to run a Java application. It contains all of the libraries and software that Java programs, and starts the Java Virtual Machine (JVM).

- [Java Runtime Environment (IBM)](https://www.ibm.com/cloud/learn/jre)
--&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;sdk&quot; tabindex=&quot;-1&quot;&gt;SDK&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/react-native-glossary/#sdk&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “SDK”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Software Development Kits (SDKs) are bundles of code to add to your application.
Third parties will often have an SDK to integrate with their service.&lt;/p&gt;
</description>
      <pubDate>Thu, 07 Oct 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/react-native-glossary/</guid>
    </item>
    <item>
      <title>What happened to @react-native-community packages?</title>
      <link>https://seanmcp.com/articles/what-happened-to-react-native-community-packages/</link>
      <description>&lt;p&gt;When React Native was first released, it included extra modules that were
helpful for mobile development like &lt;code&gt;WebView&lt;/code&gt;, &lt;code&gt;NetInfo&lt;/code&gt;, and &lt;code&gt;AsyncStorage&lt;/code&gt;.
Later in 2018,
&lt;a href=&quot;https://github.com/react-native-community/discussions-and-proposals/issues/6&quot;&gt;the RN team made the decision&lt;/a&gt;
to deprecate those internal modules and hand them off to the community to
maintain.&lt;/p&gt;
&lt;p&gt;This spawned
&lt;a href=&quot;https://github.com/react-native-community&quot;&gt;the &lt;code&gt;@react-native-community&lt;/code&gt; organization on GitHub&lt;/a&gt;
and a number of community-maintained packages like &lt;code&gt;react-native-webview&lt;/code&gt; and
&lt;code&gt;react-native-netinfo&lt;/code&gt;. If you were working in React Native in the late
20-teens, you probably remember adding these dependencies and switching out
imports.&lt;/p&gt;
&lt;p&gt;In most cases, the community proved capable to maintain current packages and
continue development. However, some packages were abandoned as requirements
changes or maintainers moved on. Alternative options popped up and gained the
support of the community, driven by individual developers or those at different
organizations like Expo, Wix, Callstack, or Software Mansion.&lt;/p&gt;
&lt;p&gt;Developers who were new to React Native might defer to &lt;code&gt;@react-native-community&lt;/code&gt;
packages, not because they were better than those alternatives but because they
appeared to be &amp;quot;the approved solution&amp;quot; from the community. That wasn&#39;t ideal for
developers, which might end up with unmaintained projects, nor for the greater
React Native community that was driving things forward.&lt;/p&gt;
&lt;p&gt;At the end of 2019, the
&lt;a href=&quot;https://github.com/react-native-community/discussions-and-proposals/issues/176&quot;&gt;&lt;code&gt;@react-native-community&lt;/code&gt; decided to move modules out of the organization&lt;/a&gt;
and into individual project organizations. In
&lt;a href=&quot;https://github.com/react-native-community/discussions-and-proposals/issues/176#issuecomment-719172928&quot;&gt;the words of one maintainer&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These modules aren&#39;t being maintained by fewer people, and aren&#39;t any less
supported. But now perception can match the reality.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a result, scoped packages like &lt;code&gt;@react-native-community/async-storage&lt;/code&gt; moved
to &lt;code&gt;react-native-async-storage/async-storage&lt;/code&gt;. But besides the name, little to
nothing else changed about how they were maintained.&lt;/p&gt;
&lt;p&gt;By offloading packages, &lt;code&gt;@react-native-community&lt;/code&gt; is free to focus on
higher-level goals for the community, like tools to discover and maintain
high-quality React Native packages. Two projects still owned by the community
organization are
&lt;a href=&quot;https://github.com/react-native-community/upgrade-helper&quot;&gt;&lt;code&gt;upgrade-helper&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;https://reactnative.directory/&quot;&gt;React Native Directory&lt;/a&gt;, both exemplifying its
new focus.&lt;/p&gt;
&lt;p&gt;So while you won&#39;t be adding &lt;code&gt;@react-native-community&lt;/code&gt; packages to your projects
going forward, that is ultimately for the best. Instead, use resources like
&lt;a href=&quot;https://reactnative.directory/&quot;&gt;React Native Directory&lt;/a&gt; or
&lt;a href=&quot;https://github.com/jondot/awesome-react-native&quot;&gt;&lt;code&gt;awesome-react-native&lt;/code&gt;&lt;/a&gt; to find
the best solution for you and your application.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;further-reading&quot; tabindex=&quot;-1&quot;&gt;Further reading&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/what-happened-to-react-native-community-packages/#further-reading&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Further reading”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/react-native-community/discussions-and-proposals/issues/6&quot;&gt;Learn Core (2018)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/react-native-community/discussions-and-proposals/issues/176&quot;&gt;What packages belong in react-native-community (2019)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/react-native-community/discussions-and-proposals/blob/master/partners/0001-organization-repository-policy.md&quot;&gt;Organization repository policy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Tue, 05 Oct 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/what-happened-to-react-native-community-packages/</guid>
    </item>
    <item>
      <title>Find an iOS simulator identifier</title>
      <link>https://seanmcp.com/articles/find-an-ios-simulator-identifier/</link>
      <description>&lt;p&gt;When running a device simulator on macOS, it is possible to navigate that
system&#39;s directly through the command line (or Finder, if you&#39;d prefer). To do
that, navigate to to the following directory:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /Library/Developer/CoreSimulator&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you look around in this directory, you will probably see a number of
subdirectories with
&lt;a href=&quot;https://en.wikipedia.org/wiki/Universally_unique_identifier&quot;&gt;UUIDs&lt;/a&gt;. Each of
these corresponds to a simulator device which contains all of the data for that
instance. In order to browse a specific simulator&#39;s files, you need to know its
ID.&lt;/p&gt;
&lt;p&gt;There are two ways to find that, one using the Xcode UI and another using the
terminal.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;through-xcode&quot; tabindex=&quot;-1&quot;&gt;Through Xcode&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/find-an-ios-simulator-identifier/#through-xcode&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Through Xcode”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;In the top menu, select &amp;quot;Window&amp;quot; &amp;gt; &amp;quot;Devices and Simulators&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;You can use the shortcut &lt;kbd&gt;shift&lt;/kbd&gt;+&lt;kbd&gt;command&lt;/kbd&gt;+&lt;kbd&gt;2&lt;/kbd&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;In the left menu of the new window, select the &amp;quot;Simulators&amp;quot; tab&lt;/li&gt;
&lt;li&gt;Select the device from the list below&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Note&lt;/strong&gt;: Make sure you match the device specs &lt;em&gt;and&lt;/em&gt; iOS version&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Look for &amp;quot;Identifier:&amp;quot; in the main panel and copy the value&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;through-the-terminal&quot; tabindex=&quot;-1&quot;&gt;Through the terminal&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/find-an-ios-simulator-identifier/#through-the-terminal&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Through the terminal”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The following command require Xcode command-line tools, which you probably
already have installed if you are running Xcode.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;From anywhere on your system, run &lt;code&gt;xcrun simctl list devices&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Find the ID from the output by iOS version and device specs and copy the ID&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the device is already running, you can save yourself some time by passing a
search argument:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Show only running simulators&lt;/span&gt;
xcrun simctl list devices booted&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That should surface the current simulator faster for copying.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;take-a-look-around!&quot; tabindex=&quot;-1&quot;&gt;Take a look around!&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/find-an-ios-simulator-identifier/#take-a-look-around!&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Take a look around!”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Once you have the simulator ID copied, you can navigate there in the terminal
with:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /Library/Developer/CoreSimulator/SIMULATOR-ID-THAT-YOU-COPIED&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, if you want to look into a specific app&#39;s bundle, you can find that
data within the simulator directory at
&lt;code&gt;./data/Containers/Bundle/Application/APP-ID&lt;/code&gt;. I have found this useful when
debugging image paths in the final app bundle.&lt;/p&gt;
&lt;p&gt;Happy browsing!&lt;/p&gt;
</description>
      <pubDate>Mon, 04 Oct 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/find-an-ios-simulator-identifier/</guid>
    </item>
    <item>
      <title>Using BEM names in React Native</title>
      <link>https://seanmcp.com/articles/using-bem-names-in-react-native/</link>
      <description>&lt;p&gt;When writing CSS classes, I prefer BEM&#39;s naming system. The pattern is clear to
read and names are easy to generate. I believe the unwieldy length of some names
is offset by the benefits.&lt;/p&gt;
&lt;p&gt;React Native doesn&#39;t use CSS but
&lt;a href=&quot;https://reactnative.dev/docs/style&quot;&gt;JSON-based stylesheets that are applied directly to elements&lt;/a&gt;.
This system has some advantages, notably
&lt;a href=&quot;https://kentcdodds.com/blog/colocation&quot;&gt;co-locating concerns&lt;/a&gt; within the
component file.&lt;/p&gt;
&lt;p&gt;But you still have to name things within you style objects, and I find myself
reaching for BEM even when removed from CSS.&lt;/p&gt;
&lt;p&gt;For a quick overview of BEM,
&lt;a href=&quot;http://getbem.com/introduction/&quot;&gt;checkout the official documentation&lt;/a&gt;. The page
is pretty short and summarizes the system with images. Okay, 1... 2... 3... I&#39;m
going to assume you&#39;re familiar with BEM.&lt;/p&gt;
&lt;p&gt;To be fair, this is perfectly valid JavaScript and works out of the box:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; styles &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; StyleSheet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&#39;message--warning&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;message__text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;View style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;warning&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; styles&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;message--warning&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message__text&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;View&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I&#39;m following the pattern from BEM of naming blocks at the top level, using
underscores for elements within a block, and hyphens for modifiers. And again,
this works fine.&lt;/p&gt;
&lt;p&gt;But I &lt;em&gt;really&lt;/em&gt; dislike using strings as properties for an object. They&#39;re
annoying to create and even worse to reference. And when we use hyphens to
create modifier names, we&#39;re stuck with &lt;code&gt;styles[&#39;message--warning&#39;]&lt;/code&gt;. I just
want to use BEM without the added discomfort of string keys. What are our
alternatives?&lt;/p&gt;
&lt;p&gt;Turns out, there aren&#39;t many options. The underscore is taken, and most special
characters are not valid in object properties. Numbers are an option, but none
of them seemed to fit. The only other option on my keyboard was, perhaps
surprisingly, the dollar sign: &lt;code&gt;$&lt;/code&gt;. (Side note: Are all currency symbols valid
for object properties?)&lt;/p&gt;
&lt;p&gt;jQuery and Svelte both use the &lt;code&gt;$&lt;/code&gt; symbol for JavaScript, so why not here in
React Native? If we swap double hyphens for double dollar signs in the previous
snippet, we get:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; styles &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; StyleSheet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;message$$warning&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;message__text&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;View style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;warning&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message$$warning &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Text style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message__text&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Text&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;View&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not bad. And I&#39;d much rather use a slightly foreign symbol in a familiar system
than string properties.&lt;/p&gt;
&lt;p&gt;What do you think: good idea or bad idea? Or should I just use styled components
already? Or maybe something else entirely? &lt;a href=&quot;https://seanmcp.com/articles/using-bem-names-in-react-native/#comment-link&quot;&gt;Let me know&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Until then, happy naming!&lt;/p&gt;
</description>
      <pubDate>Fri, 10 Sep 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/using-bem-names-in-react-native/</guid>
    </item>
    <item>
      <title>What is Hermes in React Native?</title>
      <link>https://seanmcp.com/articles/what-is-hermes-in-react-native/</link>
      <description>&lt;p&gt;React Native is framework for building Android and iOS application using React
and native capabilities. It allows developers to write JavaScript code that will
interact with platform APIs and native components to build interactive user
interfaces.&lt;/p&gt;
&lt;p&gt;To accomplish that, React Native needs an engine to run JavaScript code on
mobile devices. Apple includes
&lt;a href=&quot;https://developer.apple.com/documentation/javascriptcore&quot;&gt;JavaScriptCore (JSCore) on iOS devices&lt;/a&gt;,
but
&lt;a href=&quot;https://stackoverflow.com/questions/8374016/how-to-execute-javascript-on-android&quot;&gt;Android does not have a JavaScript engine&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So React Native included a version of JSCore in Android builds to execute
JavaScript. This resulted in larger Android application packages (APKs) for
React Native apps, and some noticeable performance issues.&lt;/p&gt;
&lt;p&gt;In 2019, the
&lt;a href=&quot;https://reactnative.dev/blog/2019/07/17/hermes&quot;&gt;React Native team announced Hermes&lt;/a&gt;
as &amp;quot;a new JavaScript engine optimized for React Native.&amp;quot; Android apps built with
React Native and Hermes were
&lt;a href=&quot;https://engineering.fb.com/2019/07/12/android/hermes/&quot;&gt;smaller, interactive faster, and used less memory&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/react-native-community/releases/blob/master/CHANGELOG.md#v0601&quot;&gt;React Native version 0.60.1&lt;/a&gt;
(2019) replaced JSCore with Hermes for Android builds. Later in version 0.64
(2021), React Native added
&lt;a href=&quot;https://reactnative.dev/blog/2021/03/12/version-0.64&quot;&gt;support for Hermes on iOS&lt;/a&gt;.
&lt;a href=&quot;https://reactnative.dev/blog/2021/03/12/version-0.64#hermes-opt-in-on-ios&quot;&gt;With one small change to your project&#39;s &lt;code&gt;Podfile&lt;/code&gt;&lt;/a&gt;,
you can include Hermes to improve your app&#39;s performance:&lt;/p&gt;
&lt;pre class=&quot;language-ruby&quot;&gt;&lt;code class=&quot;language-ruby&quot;&gt;use_react_native&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;token symbol&quot;&gt;:path&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:reactNativePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;token comment&quot;&gt;# to enable hermes on iOS, change `false` to `true` and then install pods&lt;/span&gt;
   &lt;span class=&quot;token symbol&quot;&gt;:hermes_enabled&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&#39;ll want to do some profiling of iOS apps with JSCore and Hermes before
committing to the change, but it is exciting to see more alignment between the
two platforms.&lt;/p&gt;
&lt;p&gt;To read more information about to use Hermes and how to debug it,
&lt;a href=&quot;https://reactnative.dev/docs/hermes&quot;&gt;check out the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Tue, 17 Aug 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/what-is-hermes-in-react-native/</guid>
    </item>
    <item>
      <title>Add a YouTube-embedder shortcode to your Eleventy site</title>
      <link>https://seanmcp.com/articles/add-a-youtube-embedder-shortcode-to-your-eleventy-site/</link>
      <description>&lt;p&gt;For a recent article, I wanted to add some embedded YouTube videos. Through the
share menu beneath the video, you can select &amp;quot;Embed&amp;quot; to copy and paste the code
for an &lt;code&gt;iframe&lt;/code&gt; that will load the YouTube video.&lt;/p&gt;
&lt;p&gt;That works well, but if you want to customize that code at all for embedded
videos, you need to remember to do that every time you copy and paste it into
one of your pages. Rather than fiddling with that, I decided to create a custom
shortcode to handle all of that for me.&lt;/p&gt;
&lt;p&gt;Here is the code for my Eleventy site, but with a little tweaking you could make
this work for any static-site generator:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// .eleventy.js&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addShortcode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;youtube&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;videoURL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;videoURL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;searchParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;v&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;
&amp;lt;iframe class=&quot;yt-shortcode&quot; src=&quot;https://www.youtube-nocookie.com/embed/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;id&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; title=&quot;YouTube video player&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;
      title &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; for &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;title&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&amp;lt;/iframe&gt;
&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I removed a lot of the default permissions from the YouTube embed code, and
opted for &lt;code&gt;youtube-nocookie.com&lt;/code&gt; instead to save my visitors from some tracking.
You can
&lt;a href=&quot;https://dri.es/how-to-remove-youtube-tracking&quot;&gt;read more about that on Dries Buytaert&#39;s blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With that shortcode added, you can use it in any of your template files with the
&lt;code&gt;{% youtube %}&lt;/code&gt; syntax:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- With title --&gt;&lt;/span&gt;

{% youtube &quot;https://www.youtube.com/watch?v=DhKHAopx7D0&quot;, &quot;&#39;Time Bomb&#39; by
Rancid&quot; %}

&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Without title --&gt;&lt;/span&gt;

{% youtube &quot;https://www.youtube.com/watch?v=LnaeImQ0TSg&quot; %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, I added a bit of CSS to help the videos look good on my site. These
styles might be different for your site:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;iframe.yt-shortcode&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50vw&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1rem 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;max-height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 25rem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if I want to change the way I handle YouTube embeds, I need only to change
the code in one place. Hope that helps!&lt;/p&gt;
&lt;p&gt;Happy embedding!&lt;/p&gt;
</description>
      <pubDate>Tue, 10 Aug 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/add-a-youtube-embedder-shortcode-to-your-eleventy-site/</guid>
    </item>
    <item>
      <title>Get innerHTML of Enzyme wrapper</title>
      <link>https://seanmcp.com/articles/get-innerhtml-of-enzyme-wrapper/</link>
      <description>&lt;p&gt;In Enzyme, wrapper&#39;s have a handle &lt;code&gt;.html()&lt;/code&gt; method that will return the
&lt;code&gt;outerHTML&lt;/code&gt; for that element in the tree. It&#39;s handy in the rare instance when
the markup that your code outputs needs to be precise. You can
&lt;a href=&quot;https://enzymejs.github.io/enzyme/docs/api/ShallowWrapper/html.html&quot;&gt;read more about in the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, there isn&#39;t a method that returns the &lt;code&gt;innerHTML&lt;/code&gt;. A use case I came
across for this was caring about the children of an element, but not caring
about the element itself. I didn&#39;t want this test to fail if I needed to add an
attribute to the parent element, only if the children changed.&lt;/p&gt;
&lt;p&gt;So I wrote this little helper function to grab the &lt;code&gt;innerHTML&lt;/code&gt; of a shallow
wrapper in Enzyme:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getInnerHTML&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; node&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// A text node&#39;s html method doesn&#39;t return&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// anything, so we use text instead.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; string &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; node&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There might be other strategies using some of Enzyme&#39;s built-in methods like
&lt;code&gt;.reduce()&lt;/code&gt; or &lt;code&gt;.forEach()&lt;/code&gt;, so let me know if you come up with a better
alternative.&lt;/p&gt;
&lt;p&gt;Happy testing!&lt;/p&gt;
</description>
      <pubDate>Mon, 12 Jul 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/get-innerhtml-of-enzyme-wrapper/</guid>
    </item>
    <item>
      <title>Use remark to covert markdown into HTML</title>
      <link>https://seanmcp.com/articles/use-remark-to-covert-markdown-into-html/</link>
      <description>&lt;p&gt;I&#39;ve used &lt;a href=&quot;https://npm.im/remark&quot;&gt;remark&lt;/a&gt; in a few different projects, and each
time I found it difficult to get started. For such a popular project, the
&lt;a href=&quot;https://remark.js.org/&quot;&gt;documentation is quite terse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To save myself the trouble of looking up how to do it in the future, here are
the basic steps you need to get started converting markdown to HTML with remark.&lt;/p&gt;
&lt;p&gt;First, install remark dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm i remark remark-html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will need the core library and a plugin for generating HTML. Then, import
your dependencies and use them like so:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; remark &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;remark&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; remarkHTML &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;remark-html&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; html &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;remark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;remarkHTML&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;processSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Some **markdown** text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s all you need to get going. To help jump-start your progress, checkout
this working
&lt;a href=&quot;https://replit.com/@SeanMcP/remark-example#index.js&quot;&gt;repl in Node.js&lt;/a&gt; or
&lt;a href=&quot;https://codesandbox.io/s/react-remark-example-kofy0&quot;&gt;sandbox in React&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hope this guide helps you get up and running too!&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Sat, 03 Jul 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/use-remark-to-covert-markdown-into-html/</guid>
    </item>
    <item>
      <title>Count class methods in JavaScript</title>
      <link>https://seanmcp.com/articles/count-class-methods-in-javascript/</link>
      <description>&lt;p&gt;If you have a class in JavaScript and want to know the number of methods it
contains, there are a few steps that you need to follow.&lt;/p&gt;
&lt;p&gt;Let&#39;s say we have a class like the following:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Pet&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; comes running&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We don&#39;t have handy tools like &lt;code&gt;Object.keys()&lt;/code&gt; for classes, so to count the
number of methods in our &lt;code&gt;Pet&lt;/code&gt; class, we need to first create an instance:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abby &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Pet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Abby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can pass our instance to two &lt;code&gt;Object&lt;/code&gt; methods that will grab the methods
for us:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getOwnPropertyNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;abby&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This returns an array of property names for the prototype of &lt;code&gt;abby&lt;/code&gt;, which is
the following:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;constructor&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;call&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&#39;re dealing with a simple class like the example above, you can add a
&lt;code&gt;.length&lt;/code&gt; to the end of the returned array and be done.&lt;/p&gt;
&lt;p&gt;However, if you are dealing with subclasses, you may want to go a little deeper.&lt;/p&gt;
&lt;p&gt;Let&#39;s update the example so that the class who&#39;s methods you want to count
extends another:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Pet&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; comes running&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dog&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Pet&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;pet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; wags its tail&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if we try the following code with &lt;code&gt;abby&lt;/code&gt; the &lt;code&gt;Dog&lt;/code&gt;, we get a different
answer:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abby &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Abby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getOwnPropertyNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;abby&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&#39;constructor&#39;, &#39;pet&#39;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We lost the methods on the parent &lt;code&gt;Pet&lt;/code&gt; class. To grab those too, we can create
a reusable function to dive through the prototype chain:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;countClassMethods&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; methods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; keepDiving &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; prototype &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_class&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;keepDiving&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getOwnPropertyNames&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; methods&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    prototype &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;__proto__&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; keepDiving &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; methods&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function takes a class and grabs its prototype. Then in a &lt;code&gt;while&lt;/code&gt; loop, it
iterates through the prototype&#39;s property names and adds them to a set. It then
looks ahead to the next prototype to determine whether it should continue. If
the next prototype&#39;s &lt;code&gt;__proto__&lt;/code&gt; property is falsy, then leave the loop and
return the size of the set.&lt;/p&gt;
&lt;p&gt;If you want to see a list of the methods, you could rename the function and
return &lt;code&gt;[...methods]&lt;/code&gt; or do something with &lt;code&gt;method.values()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now when I call my function with an instance of the &lt;code&gt;Dog&lt;/code&gt; class, I get the
answer that I&#39;m expecting:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; abby &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dog&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Abby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;countClassMethods&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;abby&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 3&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Values: [&#39;constructor&#39;, &#39;pet&#39;, &#39;call&#39;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a pretty niche scenario, but I hope that is helpful for someone else.&lt;/p&gt;
&lt;p&gt;Happy counting!&lt;/p&gt;
</description>
      <pubDate>Mon, 21 Jun 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/count-class-methods-in-javascript/</guid>
    </item>
    <item>
      <title>Git</title>
      <link>https://seanmcp.com/articles/git/</link>
      <description>&lt;p&gt;Here are some of the git commands that I find useful when doing by work as a
software engineer. Hopefully you will find them helpful too!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;commands&quot; tabindex=&quot;-1&quot;&gt;Commands&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/git/#commands&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Commands”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;git-checkout--&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;git checkout -&lt;/code&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/git/#git-checkout--&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “git checkout -”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Quick: Checkout the previous branch&lt;/p&gt;
&lt;p&gt;This is super handy when working with long or unwieldy branch names. With the
&lt;code&gt;-&lt;/code&gt; reference, you can convert the following set of commands into a reusable
alias:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout dev &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; pull &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout - &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; merge dev&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;git-checkout----.&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;git checkout -- .&lt;/code&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/git/#git-checkout----.&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “git checkout -- .”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Quick: Delete all changes in the current branch&lt;/p&gt;
&lt;p&gt;When you just want to start from scratch on the current branch, this command is
a huge timesaver. The &lt;code&gt;--&lt;/code&gt; refers to the current branch, while the &lt;code&gt;.&lt;/code&gt; refers to
all files. If you want to reset a particular file, you could swap the name with
the &lt;code&gt;.&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;git-commit--m-%22init%22---allow-empty&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;git commit -m &amp;quot;init&amp;quot; --allow-empty&lt;/code&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/git/#git-commit--m-%22init%22---allow-empty&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “git commit -m &amp;quot;init&amp;quot; --allow-empty”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Quick: Create a commit with no changes&lt;/p&gt;
&lt;p&gt;When starting on a development task, sometimes it&#39;s nice to set up branches and
PRs before getting started on the work. The &lt;code&gt;--allow-empty&lt;/code&gt; flag enables you to
create commits without changing any files.&lt;/p&gt;
&lt;p&gt;I use this when I have a feature branch that will be the target of bunch of
smaller branches. Initializing a those with an empty commit helps be get
organized in the beginning.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;git-diff-branch_name--s-%22todo%3A%22&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;git diff branch_name -S &amp;quot;TODO:&amp;quot;&lt;/code&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/git/#git-diff-branch_name--s-%22todo%3A%22&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “git diff branch_name -S &amp;quot;TODO:&amp;quot;”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Quick: Search the diff between the current branch and &lt;code&gt;branch_name&lt;/code&gt; for all
strings matching &lt;code&gt;TODO:&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When working on a new feature, I like to leave myself todos to address before
the branch is merged. Tracking these down can be tricky because there are other
&lt;code&gt;TODO:&lt;/code&gt;s in the codebase. I used to &lt;code&gt;grep&lt;/code&gt; through the diff, but git&#39;s &lt;code&gt;-S&lt;/code&gt; flag
is much easier.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;git-diff-branch_name--g-%22%2F*-action%22&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;git diff branch_name -G &amp;quot;/*-action&amp;quot;&lt;/code&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/git/#git-diff-branch_name--g-%22%2F*-action%22&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “git diff branch_name -G &amp;quot;/*-action&amp;quot;”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Quick: Search the diff between the current branch and &lt;code&gt;branch_name&lt;/code&gt; for all
strings matching the &lt;code&gt;/*-action&lt;/code&gt; RegEx pattern&lt;/p&gt;
&lt;p&gt;Similar to the &lt;code&gt;-S&lt;/code&gt; flag, &lt;code&gt;-G&lt;/code&gt; lets you search through the diff using RegEx. I
don&#39;t know too much about regular expressions, but it&#39;s nice to have the option
in your toolbelt.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;git-log---before%3D%222021-01-01-00%3A00%22&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;git log --before=&amp;quot;2021-01-01 00:00&amp;quot;&lt;/code&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/git/#git-log---before%3D%222021-01-01-00%3A00%22&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “git log --before=&amp;quot;2021-01-01 00:00&amp;quot;”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Quick: Limit the log output to all commits before the provided date.&lt;/p&gt;
&lt;p&gt;This is handy when you want to look at commits from a particular date or before
a date (and/or after with &lt;code&gt;--after=&lt;/code&gt;).&lt;/p&gt;
</description>
      <pubDate>Tue, 04 May 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/git/</guid>
    </item>
    <item>
      <title>Read URL search parameters with JavaScript</title>
      <link>https://seanmcp.com/articles/read-url-search-parameters-with-javascript/</link>
      <description>&lt;div id=&quot;params-message&quot; hidden=&quot;&quot;&gt;
    &lt;h2&gt;Hello search params!&lt;/h2&gt;
    &lt;p&gt;The following parameters were detected on this page:&lt;/p&gt;
    &lt;ul id=&quot;params-list&quot;&gt;&lt;/ul&gt;
    &lt;p&gt;To learn how I did this, read on or inspect the source code for this page.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Search parameters, or query strings, are handy ways to store data on URLs.
JavaScript provides an interface for reading search parameters called
&lt;code&gt;URLSearchParams&lt;/code&gt;. To use it, create an instance with the &lt;code&gt;new&lt;/code&gt; keyword and pass
your search parameter string as an argument:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; params &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;?name=Sam&amp;amp;name=Ezra&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; usp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URLSearchParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The returned &lt;code&gt;URLSearchParams&lt;/code&gt; object has a few
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams#methods&quot;&gt;a bunch of useful methods&lt;/a&gt;,
but we&#39;re going to focus on three:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get()&lt;/code&gt;: Returns the first value for a particular key&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getAll()&lt;/code&gt;: Returns all of the values for a particular key&lt;/li&gt;
&lt;li&gt;&lt;code&gt;forEach()&lt;/code&gt;: Iterates over keys with a callback that receives &lt;code&gt;value&lt;/code&gt; and
&lt;code&gt;key&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If I call the &lt;code&gt;get()&lt;/code&gt; method for &lt;code&gt;name&lt;/code&gt;, then it will return the first value
from my search parameter string:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;usp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// &#39;Sam&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you are dealing with unique parameters, this method is all you need to get
the job done. But in our example, there are multiple names being passed. To
retrieve all of those values, we will call &lt;code&gt;getAll()&lt;/code&gt; with &lt;code&gt;name&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;usp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&#39;Sam&#39;, &#39;Ezra&#39;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are working with a few exact keys, you can probably stop there. But if
you are dealing with a lot of keys or just want an easier way to read search
parameters, you can use a helper function that iterates over all of the keys and
stores them in an object:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/**
 * Read the search parameters from window location
 */&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;readSearchParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; usp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URLSearchParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;location&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;search&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; params &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  usp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      params&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    params&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; params&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then call the function whenever you need to reference the current location&#39;s
search parameters:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// https://seanmcp.com/articles/read-url-search-parameters-with-javascript/&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ?greeting=Hello&amp;amp;name=World&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; params &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;readSearchParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;greeting&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// [&#39;Hello&#39;]&lt;/span&gt;
params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//[&#39;World&#39;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To see it in action, try going to &lt;a href=&quot;https://seanmcp.com/articles/read-url-search-parameters-with-javascript/&quot;&gt;that url&lt;/a&gt;, or
try adding your own search parameters.&lt;/p&gt;
&lt;p&gt;Happy reading!&lt;/p&gt;
</description>
      <pubDate>Sat, 01 May 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/read-url-search-parameters-with-javascript/</guid>
    </item>
    <item>
      <title>Fix &#39;downloadable font: rejected by sanitizer&#39; error in Firefox</title>
      <link>https://seanmcp.com/articles/fix-downloadable-font-rejected-by-sanitizer-error-in-firefox/</link>
      <description>&lt;p&gt;I ran into an issue today when I tried to serve a typeface I downloaded from
Google Fonts. When I added the files and &lt;code&gt;@font-face&lt;/code&gt; rules to my CSS, I got the
following error in the Firefox console:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;downloadable font: rejected by sanitizer
    (font-family: &amp;quot;Inter&amp;quot; style:normal weight:400 stretch:100 src index:0)
    source: http://localhost:8080/fonts/Inter-Regular.ttf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Chrome console had nothing, so I figured this was a Firefox issue. After
some searching around, I learned that
&lt;a href=&quot;https://support.mozilla.org/en-US/questions/913498&quot;&gt;Firefox is checking&lt;/a&gt; that a
font file is valid before loading it, which can protect you against some
attacks.&lt;/p&gt;
&lt;p&gt;Inter is a pretty popular typeface, so I ruled out corrupt or malicious font
files. Further digging lead me to some solutions, but
&lt;a href=&quot;https://github.com/FortAwesome/Font-Awesome/issues/8078&quot;&gt;they seemed&lt;/a&gt;
&lt;a href=&quot;https://stackoverflow.com/questions/57835543/how-to-fix-downloadable-font-rejected-by-sanitizer&quot;&gt;situation specific&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was prepared to live with the error, when I gave it one last look. The source
url (which I&#39;ve wrapped here but was broken on two lines in the console) was
incorrect. The path to the font files should have been
&lt;code&gt;assets/fonts/Inter-Regular.ttf&lt;/code&gt;. Fixing that path in &lt;code&gt;@font-face&lt;/code&gt;&#39;s &lt;code&gt;src&lt;/code&gt;
resolved the issue.&lt;/p&gt;
&lt;p&gt;If you encounter a similar error, check to make sure that the path to your font
file is correct. It would be helpful if the message was more descriptive:
&amp;quot;downloadable font: rejected by sanitizer (file not found)&amp;quot;.&lt;/p&gt;
&lt;p&gt;Happy font serving!&lt;/p&gt;
</description>
      <pubDate>Thu, 01 Apr 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-downloadable-font-rejected-by-sanitizer-error-in-firefox/</guid>
    </item>
    <item>
      <title>Fix Netlify CMS YAML error &#39;Implicit map keys need to be on a single line&#39;</title>
      <link>https://seanmcp.com/articles/fix-netlify-cms-yaml-error-implicit-map-keys-need-to-be-on-a-single-line/</link>
      <description>&lt;p&gt;When trying to setup Netlify CMS on a project, I kept getting this error on the
&lt;code&gt;/admin&lt;/code&gt; page:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error loading the CMS configuration
Config Errors:

YAMLSemanticError: Implicit map keys need to be on a single line at line 1, column 1:

&amp;lt;!DOCTYPE html&amp;gt;
^^^^^^^^^^^^^^^…

Check your config.yml file.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I checked and doubled checked the YAML in my &lt;code&gt;config.yml&lt;/code&gt; file, and everything
was valid. I went through the Netlify Identity steps to verify that they were
followed correctly, but that didn&#39;t help either.&lt;/p&gt;
&lt;p&gt;Googling the error message brought up nothing useful.&lt;/p&gt;
&lt;p&gt;Then it occurred to me: &amp;quot;What if Netlify CMS isn&#39;t getting the config file at
all?&amp;quot;&lt;/p&gt;
&lt;p&gt;Sure enough, my static-site generator was skipping the unrecognized &lt;code&gt;.yml&lt;/code&gt; file
when building the site. I added the configuration to copy that file to the build
folder, and &lt;em&gt;voilà&lt;/em&gt;: everything works as expected.&lt;/p&gt;
&lt;p&gt;So if you are getting the same error, check to make sure that the &lt;code&gt;config.yml&lt;/code&gt;
file is making it to your built &lt;code&gt;admin/&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;Happy debugging!&lt;/p&gt;
</description>
      <pubDate>Thu, 25 Mar 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-netlify-cms-yaml-error-implicit-map-keys-need-to-be-on-a-single-line/</guid>
    </item>
    <item>
      <title>Copy the last git commit hash on macOS</title>
      <link>https://seanmcp.com/articles/copy-the-last-git-commit-hash-on-macos/</link>
      <description>&lt;p&gt;When responding to code-review requests, I like to point the reviewer to the
specific commit where the issue was addressed with a message like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fixed in 4908c91a06258814077b1358210eb78cc718609c&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GitHub will automatically detect the hash, shorten it, and convert it into a
link to the commit view.&lt;/p&gt;
&lt;p&gt;Rather than going into &lt;code&gt;git log&lt;/code&gt; and copying the hash manually, I use the
following one-liner in the terminal on macOS:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; rev-parse HEAD &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; pbcopy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first half of the command returns the last commit hash from
&lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Git-References#ref_the_ref&quot;&gt;&lt;code&gt;HEAD&lt;/code&gt;&lt;/a&gt;,
which is a reference to the current branch. You could use
&lt;code&gt;git rev-parse name_of_branch&lt;/code&gt; too, but that is often longer to type.&lt;/p&gt;
&lt;p&gt;The output of &lt;code&gt;git rev-parse&lt;/code&gt; is then piped to
&lt;a href=&quot;https://ss64.com/osx/pbcopy.html&quot;&gt;&lt;code&gt;pbcopy&lt;/code&gt;&lt;/a&gt;, the clipboard utility for macOS.
If you were using a different platform like Unix or Windows, there are
&lt;a href=&quot;https://stackoverflow.com/questions/749544/pipe-to-from-the-clipboard-in-bash-script&quot;&gt;other options for you&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To save some more time, I added an alias my shell&#39;s rc file:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# git last commit (hash)&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;glc&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;git rev-parse HEAD | pbcopy&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Happy copying!&lt;/p&gt;
</description>
      <pubDate>Wed, 24 Mar 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/copy-the-last-git-commit-hash-on-macos/</guid>
    </item>
    <item>
      <title>Add Heroicons to an Eleventy site</title>
      <link>https://seanmcp.com/articles/add-heroicons-to-an-eleventy-site/</link>
      <description>&lt;p&gt;In a recent &lt;a href=&quot;https://11ty.dev&quot;&gt;Eleventy&lt;/a&gt; project, I wanted an easy way to add
&lt;a href=&quot;https://heroicons.com&quot;&gt;Heroicons&lt;/a&gt;. That lead me to creating an Eleventy plugin
that adds some handy Heroicon shortcodes. Here&#39;s how to get started:&lt;/p&gt;
&lt;p&gt;First, install
&lt;a href=&quot;https://npm.im/eleventy-plugin-heroicons&quot;&gt;&lt;code&gt;eleventy-plugin-heroicons&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; i &lt;span class=&quot;token parameter variable&quot;&gt;-D&lt;/span&gt; eleventy-plugin-heroicons&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, add the plugin to your &lt;code&gt;.eleventy.js&lt;/code&gt; settings file with any other
plugins:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// .eleventy.js&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPlugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;eleventy-plugin-heroicons&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, you are ready to use the &lt;code&gt;heroicon&lt;/code&gt; shortcode. Head over to
a markdown or template file and try it out:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- contact.md --&gt;&lt;/span&gt;

&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; {% heroicon &quot;outline&quot;, &quot;mail&quot; %} Send me an email&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: These examples are using Nunjucks syntax. If you are using Liquid, you
can reference the official documentation for examples.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;heroicon&lt;/code&gt; shortcode takes a few arguments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The style of icon (outline or solid)&lt;/li&gt;
&lt;li&gt;The name of the icon&lt;/li&gt;
&lt;li&gt;An optional alt tag for the SVG&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To save yourself a bit of time, you can use the &lt;code&gt;heroicon_outline&lt;/code&gt; or
&lt;code&gt;heroicon_solid&lt;/code&gt; shortcodes which pass the style automatically. We could replace
the previous example with:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- contact.md --&gt;&lt;/span&gt;

&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; {% heroicon_outline &quot;mail&quot; %} Send me an email&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it would work the same.&lt;/p&gt;
&lt;p&gt;If you use the shortcode without alt text, and &lt;code&gt;aria-hidden=&amp;quot;true&amp;quot;&lt;/code&gt; attribute is
applied to the &lt;code&gt;svg&lt;/code&gt; element. When alt text is provided, a &lt;code&gt;title&lt;/code&gt; element is
added as the first child to the &lt;code&gt;svg&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Input --&gt;&lt;/span&gt;
{% heroicon_outline &quot;heart&quot;, &quot;Love&quot; %}

&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Output --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;svg&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2000/svg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;none&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;viewBox&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0 0 24 24&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;currentColor&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;data-heroicon-name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;heart&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token attr-name&quot;&gt;data-heroicon-style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;outline&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Love&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;path&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;stroke-linecap&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;round&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;stroke-linejoin&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;round&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;stroke-width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;svg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will enable screen-reader and other assistive technology users to
understand what the icon represents. Without an alt tag, you&#39;ll want to make
sure that the meaning can be derived from context:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  {% heroicon_solid &quot;plus&quot; %}
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Add item&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  {% heroicon_solid &quot;x&quot; %}
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visually-hidden&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Close menu&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of the icons have &lt;code&gt;data-heroicon-name&lt;/code&gt; and &lt;code&gt;data-heroicon-style&lt;/code&gt; attributes
applied to the &lt;code&gt;svg&lt;/code&gt; that you can use for styling:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;[data-heroicon-style=&quot;outline&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 24px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;[data-heroicon-style=&quot;solid&quot;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 20px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;[data-heroicon-name]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 2px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&#39;d prefer to use a class name, you can pass one on a configuration object
while adding the plugin:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// .eleventy.js&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPlugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;eleventy-plugin-heroicons&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;icon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is also
&lt;a href=&quot;https://github.com/SeanMcP/eleventy-plugin-heroicons#configuration&quot;&gt;an option to &lt;code&gt;errorOnMissing&lt;/code&gt; icons&lt;/a&gt;,
which might be nice to ensure that all icons display as intended.&lt;/p&gt;
&lt;p&gt;Hopefully that helps! Let me know if you have any suggestions for the package.
&lt;a href=&quot;https://github.com/SeanMcP/eleventy-plugin-heroicons/pulls&quot;&gt;PRs are most welcome &lt;e-moji label=&quot;smiles&quot;&gt;😊&lt;/e-moji&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Tue, 09 Mar 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/add-heroicons-to-an-eleventy-site/</guid>
    </item>
    <item>
      <title>Create a URL shortener with Netlify</title>
      <link>https://seanmcp.com/articles/create-a-url-shortener-with-netlify/</link>
      <description>&lt;p&gt;After hearing of a few people doing the same, I set up a mostly-free URL
shortener with Netlify: &lt;a href=&quot;https://smcp.dev&quot;&gt;smcp.dev&lt;/a&gt;. Here&#39;s the steps I
followed to get it done.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;1.-register-a-domain&quot; tabindex=&quot;-1&quot;&gt;1. Register a domain&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-url-shortener-with-netlify/#1.-register-a-domain&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “1. Register a domain”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Go to your favorite registrar and buy a new domain. Aim for something short and
memorable, and consider the &lt;code&gt;.link&lt;/code&gt; TLD. I heard a recommendation for
&lt;a href=&quot;https://hover.com&quot;&gt;Hover&lt;/a&gt;, which seems pretty cool, but I went with Google
Domains for smcp.dev.&lt;/p&gt;
&lt;p&gt;This is the only step that costs money, and the amount will depend on the
domain/TLD that you choose. &lt;code&gt;.dev&lt;/code&gt; TLDs on Google Domains cost $12/year.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;2.-create-a-repo&quot; tabindex=&quot;-1&quot;&gt;2. Create a repo&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-url-shortener-with-netlify/#2.-create-a-repo&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “2. Create a repo”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I modelled &lt;a href=&quot;https://github.com/seanmcp/smcp.dev&quot;&gt;my repo&lt;/a&gt; off of
&lt;a href=&quot;https://github.com/cassidoo/cass.run&quot;&gt;&lt;code&gt;cassidoo/cass.run&lt;/code&gt;&lt;/a&gt;, which seems to be
based off of
&lt;a href=&quot;https://github.com/kentcdodds/netlify-shortener-example&quot;&gt;kentcdodds/netlify-shortener-example&lt;/a&gt;.
In order of importance, you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;_redirect&lt;/code&gt; file that maps short urls to destinations,&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;package.json&lt;/code&gt; with a single (optional) dependency for adding links,&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;README.md&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;and some git stuff.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;3.-add-your-project-to-netlify&quot; tabindex=&quot;-1&quot;&gt;3. Add your project to Netlify&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-url-shortener-with-netlify/#3.-add-your-project-to-netlify&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “3. Add your project to Netlify”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Login to Netlify (or create an account) and add a new project from git. Select
your repository, and enter the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build command&lt;/strong&gt;: Nothing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Publish directory&lt;/strong&gt;: Nothing&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;4.-setup-your-custom-domain&quot; tabindex=&quot;-1&quot;&gt;4. Setup your custom domain&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-url-shortener-with-netlify/#4.-setup-your-custom-domain&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “4. Setup your custom domain”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In the main project view on Netlify, select &amp;quot;&lt;e-moji&gt;⚙️&lt;/e-moji&gt; Domain
settings&amp;quot;, then &amp;quot;Add custom domain&amp;quot;. Enter the domain that you registered in
step one and go through the flow.&lt;/p&gt;
&lt;p&gt;You&#39;ll need to update the DNS settings with your registrar to point to Netlify&#39;s
servers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns1.p05.nsone.net
dns2.p05.nsone.net
dns3.p05.nsone.net
dns4.p05.nsone.net
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;5.-wait&quot; tabindex=&quot;-1&quot;&gt;5. Wait&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-url-shortener-with-netlify/#5.-wait&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “5. Wait”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Depending on how quickly you went through steps 1-4, you may have to wait a few
hours for everything to get setup from registrar and the DNS. For me, this took
about thirty minutes, but your mileage may vary.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;6.-enjoy&quot; tabindex=&quot;-1&quot;&gt;6. Enjoy&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-url-shortener-with-netlify/#6.-enjoy&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “6. Enjoy”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;With all that in place, you should be able to use your URL shortener:
&lt;a href=&quot;https://smcp.dev/yt&quot;&gt;smcp.dev/yt&lt;/a&gt;! To add a new URL, you can add a new line to
the &lt;code&gt;_redirect&lt;/code&gt; file manually or use the
&lt;a href=&quot;https://github.com/kentcdodds/netlify-shortener#usage&quot;&gt;&lt;code&gt;shorten&lt;/code&gt; script&lt;/a&gt;(if you
added it)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Happy shortening!&lt;/p&gt;
</description>
      <pubDate>Fri, 26 Feb 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/create-a-url-shortener-with-netlify/</guid>
    </item>
    <item>
      <title>Set innerHTML of an element in Svelte</title>
      <link>https://seanmcp.com/articles/set-innerhtml-of-an-element-in-svelte/</link>
      <description>&lt;p&gt;When working on a Svelte application, I wanted to replace newline characters in
a string with &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; elements and render the result as HTML. If you do the
replace in your component markup, then the rendered output has escaped angle
brackets:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Component.svelte --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{notes.replace(/&#92;n/g, &#39;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;br&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&#39;)}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Output markup --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Line one&lt;span class=&quot;token entity named-entity&quot; title=&quot;&amp;lt;&quot;&gt;&amp;amp;lt;&lt;/span&gt;br&lt;span class=&quot;token entity named-entity&quot; title=&quot;&amp;gt;&quot;&gt;&amp;amp;gt;&lt;/span&gt;Line two&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From previous experience, I know that we&#39;re not rendering the replaced string as
HTML, so I tried searching online for a solution involving &lt;code&gt;innerHTML&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the Svelte API docs, there are only three mentions of &lt;code&gt;innerHTML&lt;/code&gt;, two of
which refer to bindings with &lt;code&gt;contenteditable&lt;/code&gt; elements. But I wanted to set the
&lt;code&gt;innerHTML&lt;/code&gt; of an element that would never change.&lt;/p&gt;
&lt;p&gt;While searching through the Svelte Discord for &lt;code&gt;innerHTML&lt;/code&gt;, I came across an
unrelated post that mentioned &lt;code&gt;{@html}&lt;/code&gt;. I had never encountered this before, so
I looked it up in the Svelte docs&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/set-innerhtml-of-an-element-in-svelte/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In a text expression, characters like &lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt; are escaped; however, with
HTML expressions, they&#39;re not.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not the longest explanation, but that sounds like my problem. Back in my code, I
tried wrapping the replaced text with &lt;code&gt;{@html}&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Component.svelte --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;{@html notes.replace(/&#92;n/g, &#39;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;br&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&#39;)}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, everything rendered as expected:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Output markup --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  Line one&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;br&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  Line two
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So next time you want to set the &lt;code&gt;innerHTML&lt;/code&gt; of an element in Svelte, use an
HTML express with &lt;code&gt;{@html}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Happy escaping!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://svelte.dev/docs#html&quot;&gt;https://svelte.dev/docs#html&lt;/a&gt; &lt;a href=&quot;https://seanmcp.com/articles/set-innerhtml-of-an-element-in-svelte/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Thu, 25 Feb 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/set-innerhtml-of-an-element-in-svelte/</guid>
    </item>
    <item>
      <title>Let&#39;s stop skinning cats</title>
      <link>https://seanmcp.com/articles/lets-stop-skinning-cats/</link>
      <description>&lt;p&gt;Idioms are interesting. They&#39;re phrases that have a functional meaning that is
independent of their literal meaning. In English, we have idioms like &amp;quot;beating
around the bush,&amp;quot; which means to avoid saying what you really mean because it&#39;s
uncomfortable &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/lets-stop-skinning-cats/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;When I was teaching a classroom of first- and second-generation Americans, we
explicitly taught idioms so that students would understand the form if not
remember examples when reading or speaking with others. I had an illustrated
poster on the wall with some common US idioms.&lt;/p&gt;
&lt;p&gt;Someone could certainly go on a crusade to rid a language of idioms. &amp;quot;Why say
something purposely incorrect when you really mean something else?&amp;quot; they could
argue. I&#39;m not going to go that far; I think learning of
&lt;a href=&quot;https://www.thatsanegg.com/about&quot;&gt;idioms in other languages in kind of neat&lt;/a&gt;.
That said, there is one English idiom that I would like to remove:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is more than one way to skin a cat. &lt;e-moji&gt;😿&lt;/e-moji&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you are unfamiliar, the idiom means that there are multiple ways to complete
a particular task. Since that is an axiom of sorts in programming,
&lt;a href=&quot;https://duckduckgo.com/?q=site%3Astackoverflow.com+%22more+than+one+way+to+skin+a+cat%22&quot;&gt;I see the idiom used relatively frequently&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Where it differs from an idiom like &amp;quot;barking up the wrong tree,&amp;quot; is that the
literal meaning of &amp;quot;skinning a cat&amp;quot; is so odd. Sure, you &lt;em&gt;can&lt;/em&gt; skin a cat. But
who does that?&lt;/p&gt;
&lt;p&gt;I am not very old, nor have I had a vast set of life experiences. But I have
never once needed to, seen, or heard of anyone skinning a cat. I don&#39;t know of
any uses for cat fur, so skinning one seems unnecessary. Also, many people like
cats and a phrase that involves removing their skin is a little insensitive.&lt;/p&gt;
&lt;p&gt;I propose replacing this idiom with another:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is more than one way to bake a cake. &lt;e-moji&gt;🍰&lt;/e-moji&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This works on multiple levels. One, cakes are fun. Two, most people have heard
of baking cakes and may have baked one themselves. And three, it doesn&#39;t involve
skinning a beloved animal. And four,
&lt;a href=&quot;https://www.allrecipes.com/search/results/?sort=re&amp;amp;wt=cake&quot;&gt;there &lt;em&gt;is&lt;/em&gt; more than one way to make a cake&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;At the end of the day, I don&#39;t care all that much. But I have started using
&amp;quot;there is more than one way to bake a cake&amp;quot; in personal and professional
conversations, and I haven&#39;t (to my knowledge) been misunderstood. So why not?
Language is what we make of it, so let&#39;s make English a little more fun.&lt;/p&gt;
&lt;p&gt;Happy baking!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I&#39;ve made my way to this website on a number of occasions, and I think it&#39;s
neat: &lt;a href=&quot;https://www.ef.com/ca/english-resources/english-idioms/&quot;&gt;https://www.ef.com/ca/english-resources/english-idioms/&lt;/a&gt; &lt;a href=&quot;https://seanmcp.com/articles/lets-stop-skinning-cats/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Thu, 18 Feb 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/lets-stop-skinning-cats/</guid>
    </item>
    <item>
      <title>Search all files for two strings</title>
      <link>https://seanmcp.com/articles/search-all-files-for-two-strings/</link>
      <description>&lt;p&gt;To search the current directory for all files that contain two independent
strings, you can use the following terminal command:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-lr&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;common&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-lr&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rare&quot;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In essence, this is saying &amp;quot;Recursively find all the files in the current
directory with the string &lt;code&gt;rare&lt;/code&gt;, and then look through those files to find any
with the string &lt;code&gt;common&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Depending on the directory, you may want to limit the number of directories that
&lt;code&gt;grep&lt;/code&gt; has to inspect. For me, that often includes directories like
&lt;code&gt;node_modules/&lt;/code&gt; and &lt;code&gt;cache&lt;/code&gt;. Here&#39;s the same command with a few excluded
directories:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-lr&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;common&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-lr&lt;/span&gt; --exclude-dir&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;node_modules --exclude-dir&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;.git --exclude-dir&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;build --exclude-dir&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;cache &lt;span class=&quot;token string&quot;&gt;&quot;rare&quot;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The order of the strings does matter, but putting the less commonly occurring
string second is a little more efficient.&lt;/p&gt;
&lt;p&gt;Happy searching!&lt;/p&gt;
</description>
      <pubDate>Mon, 15 Feb 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/search-all-files-for-two-strings/</guid>
    </item>
    <item>
      <title>Fix &quot;Error: Could not resolve pagination key in template data&quot; in Eleventy</title>
      <link>https://seanmcp.com/articles/fix-error-could-not-resolve-pagination-key-in-template-data-in-eleventy/</link>
      <description>&lt;p&gt;In a recent Eleventy project, I wanted to create a single collection for tags
with two keys: &lt;code&gt;alphabetical&lt;/code&gt; for an array of all tags, and &lt;code&gt;popular&lt;/code&gt; for an
array of arrays with the tag and number of times it was used.&lt;/p&gt;
&lt;p&gt;To access either &amp;quot;sub-collection&amp;quot;, I could dive into the object like
&lt;code&gt;collections.tagList.alphabetical&lt;/code&gt;. This worked like a dream in my template and
markdown files, and I thought maybe I was on to a new cool pattern for Eleventy.&lt;/p&gt;
&lt;p&gt;But when I tried to paginate the sub-collection, everything fell apart. Eleventy
errored with the following message:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;Problem writing Eleventy templates: &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;more &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; DEBUG output&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Could not resolve pagination key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; template data: collections.tagList.alphabetical

&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;Error&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; was thrown:
    Error: Could not resolve pagination key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; template data: collections.tagList.alphabetical&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pagination code in question looked like:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; collections.tagList.alphabetical
  &lt;span class=&quot;token key atrule&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; tag
&lt;span class=&quot;token key atrule&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /tag//&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interesting. Maybe the collection hasn&#39;t been created by the time the pagination
code runs, I guessed. To test this, I tried paginating &lt;code&gt;collections.tagList&lt;/code&gt; to
see if the &lt;code&gt;alphabetical&lt;/code&gt; key was present:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; collections.tagList
  &lt;span class=&quot;token key atrule&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; tag
&lt;span class=&quot;token key atrule&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /tag//&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This created pages for &lt;code&gt;alphabetical&lt;/code&gt; and &lt;code&gt;popular&lt;/code&gt;, which proved my hypothesis
wrong: the alphabetical data does exist when the pagination occurs.&lt;/p&gt;
&lt;p&gt;Maybe it had something to do with paginating nested objects? To confirm, I added
a test object to the frontmatter and tried to paginate it:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; test.test.test
  &lt;span class=&quot;token key atrule&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; tag
&lt;span class=&quot;token key atrule&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /tag//
&lt;span class=&quot;token key atrule&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This worked as expected, creating pages for a, b, and c. So it isn&#39;t an issue
with paginating deep objects.&lt;/p&gt;
&lt;p&gt;With two incorrect hypotheses, it was time to look for outside help. I
&lt;a href=&quot;https://discord.com/channels/741017160297611315/741017160297611319/807589091814146060&quot;&gt;posted in 11ty Discord&lt;/a&gt;
and did some searching. My initial queries brought up two issues:
&lt;a href=&quot;https://github.com/11ty/eleventy/issues/171&quot;&gt;an actual bug from 2018&lt;/a&gt; and
&lt;a href=&quot;https://github.com/11ty/eleventy/issues/690&quot;&gt;some invalid JSON from 2019&lt;/a&gt;.
Neither of which provided the solution here.&lt;/p&gt;
&lt;p&gt;Feeling at a dead end, I decided to rethink the problem. I couldn&#39;t paginate
over a nested collection object, but normal collections work just fine. If I
could flatten my clever &lt;code&gt;tagsList&lt;/code&gt; into multiple collections, the problem would
be solved.&lt;/p&gt;
&lt;p&gt;Instead of &lt;code&gt;collections.tagList.alphabetical&lt;/code&gt; and &lt;code&gt;collections.tagList.popular&lt;/code&gt;,
I created two collections: &lt;code&gt;collections.tagsAll&lt;/code&gt; and &lt;code&gt;collections.tagsPopular&lt;/code&gt;.
This required an addition iteration over the post data (one for each
collection), but that small increase in build time isn&#39;t an issue for this
project.&lt;/p&gt;
&lt;p&gt;The final code to fix the &amp;quot;Error: could not resolve pagination key in template
data&amp;quot; is a flattened collection:&lt;/p&gt;
&lt;pre class=&quot;language-md&quot;&gt;&lt;code class=&quot;language-md&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;pagination&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; collections.tagsAll
  &lt;span class=&quot;token key atrule&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; tag
&lt;span class=&quot;token key atrule&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /tag//&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works well, but I would still love to find a way to get the original
solution to work. Let me know if you have a better way to solve this problem.
&lt;e-moji&gt;👍&lt;/e-moji&gt;&lt;/p&gt;
&lt;p&gt;Happy paginating!&lt;/p&gt;
</description>
      <pubDate>Sat, 06 Feb 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-error-could-not-resolve-pagination-key-in-template-data-in-eleventy/</guid>
    </item>
    <item>
      <title>Geddes&#39; Guide to Crafting</title>
      <link>https://seanmcp.com/articles/dave-geddes-guide-to-crafting/</link>
      <description>&lt;p&gt;I spent some time this week enjoying
&lt;a href=&quot;https://mastery.games&quot;&gt;Dave Geddes&#39; content&lt;/a&gt;. Three resources in particular
have left me with a lot to think about, and I&#39;m combining them into what I call
&amp;quot;Geddes&#39; Guide to Crafting&amp;quot;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mastery.games/post/practice-css/&quot;&gt;&lt;em&gt;Practice CSS Like an Artist&lt;/em&gt; (article)&lt;/a&gt;:
Geddes&#39; draws comparisons between designing an application and painting a
portrait. First you start with a rough sketch, then filling with broad
strokes. Only once you have the foundation set do you add fine details.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mastery.games/post/polish/&quot;&gt;&lt;em&gt;When Should You Polish Your UI?&lt;/em&gt; (article)&lt;/a&gt;:
Geddes reflects of a few strategies for polishing the design for your
application. Following the previous theme, he recommends a rough sketch with
broad strokes (&lt;em&gt;i.e&lt;/em&gt; prototyping) before polishing with fine details.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=7zBpd3wWsnU&quot;&gt;&lt;em&gt;Build the zelda UI with Web Tech&lt;/em&gt; (video)&lt;/a&gt;:
Geddes completes the first phase of recreating Zelda: Breath of the Wild&#39;s
menu screen in HTML and CSS. Here you can see rough sketching and broad
strokes in practice. The video alludes to a part two, but it was never posted
on YouTube.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a developer, it can be tempting to spend too much time worrying about the
fine details of what you are developing. But the best of products were not
created perfect on the first try. They come from an on-going process of
sketching, filling, and eventually polish.&lt;/p&gt;
&lt;p&gt;So don&#39;t sweat the fine details in the beginning. Create a something that works,
and then fill in those details later.&lt;/p&gt;
&lt;p&gt;Happy crafting!&lt;/p&gt;
</description>
      <pubDate>Fri, 29 Jan 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/dave-geddes-guide-to-crafting/</guid>
    </item>
    <item>
      <title>Send data to the window with Eleventy</title>
      <link>https://seanmcp.com/articles/send-data-to-the-window-with-eleventy/</link>
      <description>&lt;p&gt;Static-site generators like Eleventy are great at building websites. But when
you want to add additional functionality, like a search feature, it might feel
like they fall short.&lt;/p&gt;
&lt;p&gt;All the data to generate your site exists at build time, how can you access that
with some client-side JavaScript?&lt;/p&gt;
&lt;p&gt;Here we&#39;ll look at one solution with Eleventy to expose data on the global
&lt;code&gt;window&lt;/code&gt; object to add interactive elements to your static site.&lt;/p&gt;
&lt;p&gt;Besides familiarity with Eleventy, the only prerequisite here is
&lt;a href=&quot;https://www.11ty.dev/docs/shortcodes/#universal-shortcodes&quot;&gt;creating custom shortcodes&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;nunjucks&quot; tabindex=&quot;-1&quot;&gt;Nunjucks&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/send-data-to-the-window-with-eleventy/#nunjucks&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Nunjucks”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Out-of-the-box, you can use Nunjucks&#39; &lt;code&gt;dump&lt;/code&gt; and &lt;code&gt;safe&lt;/code&gt; filters to stringify
data and leave it unescaped, respectively. Put that all within a &lt;code&gt;script&lt;/code&gt; tag,
and you have a simple method for exposing data:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- index.njk --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;
  window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;__DATA__ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;hello&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;there&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; dump &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; safe &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works but is a little fiddly and limited to Nunjucks. For a more universal
solution, let&#39;s create a custom shortcode.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;shortcode&quot; tabindex=&quot;-1&quot;&gt;Shortcode&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/send-data-to-the-window-with-eleventy/#shortcode&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Shortcode”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A better solution to send data to the client is with a reusable shortcode. Let&#39;s
add a it to &lt;code&gt;.eleventy.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// .eleventy.js&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addShortcode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;expose&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;script&gt;
            window.__DATA__=JSON.parse(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;);
        &amp;lt;/script&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then use the new shortcode like so:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- index.njk --&gt;&lt;/span&gt;
{% expose [&#39;hello&#39;, &#39;there&#39;] %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nice and simple! I&#39;m going to offer an optional improvement to cleanup after
exposing the data:&lt;/p&gt;
&lt;!-- ```js/1,3 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addShortcode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;expose&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;script id=&quot;__EXPOSE__&quot;&gt;
        window.__DATA__=JSON.parse(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;);
        document.getElementById(&quot;__EXPOSE__&quot;).remove();
    &amp;lt;/script&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With those changes, the script will execute on the client, add the data to the
&lt;code&gt;window&lt;/code&gt;, and then remove the &lt;code&gt;script&lt;/code&gt; tag.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Hope that helps! Let me know if you have a better method of exposing data on the
&lt;code&gt;window&lt;/code&gt;, or how you can accomplish this with your favorite static-site
generator.&lt;/p&gt;
&lt;p&gt;Happy scripting!&lt;/p&gt;
</description>
      <pubDate>Mon, 25 Jan 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/send-data-to-the-window-with-eleventy/</guid>
    </item>
    <item>
      <title>Checkout the previous git branch</title>
      <link>https://seanmcp.com/articles/checkout-the-previous-git-branch/</link>
      <description>&lt;p&gt;Today I needed to checkout a branch, pull the latest, then checkout &lt;code&gt;dev&lt;/code&gt;, pull
the latest, and merge &lt;code&gt;dev&lt;/code&gt; into my branch.&lt;/p&gt;
&lt;p&gt;This flow is pretty typical of my work, but I wondered: is there an easier way
to go back to the previous branch in git?&lt;/p&gt;
&lt;p&gt;Turns out there is, and
&lt;a href=&quot;https://stackoverflow.com/a/7207542/8486161&quot;&gt;StackOverflow came to the rescue&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout -&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will checkout the most recent branch. For more of an explanation,
read the full response on StackOverflow.&lt;/p&gt;
&lt;p&gt;To complete the steps above, I could run the following commands:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout feature/branch-with-a-long-name
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; pull
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout dev
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; pull
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout -
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; merge dev&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I can remember that command, it will be more efficient that going back
through my command history. Hope that helps you too!&lt;/p&gt;
&lt;p&gt;Happy version controlling!&lt;/p&gt;
</description>
      <pubDate>Fri, 22 Jan 2021 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/checkout-the-previous-git-branch/</guid>
    </item>
    <item>
      <title>Make all properties required in TypeScript</title>
      <link>https://seanmcp.com/articles/make-all-properties-required-in-typescript/</link>
      <description>&lt;p&gt;I have a type interface for shapes that looks something like this:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  height&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  width&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I want to extend my interface for rectangles, but I want both &lt;code&gt;height&lt;/code&gt; and
&lt;code&gt;width&lt;/code&gt; to be required. You can do that in TypeScript with a
&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype&quot;&gt;&lt;code&gt;Required&lt;/code&gt; utility type&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Required&lt;/code&gt; takes a type and returns one with all required properties. You can
use it by declaring a new &lt;code&gt;type&lt;/code&gt; and passing the &lt;code&gt;Shape&lt;/code&gt; interface:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Rectangle&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Required&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Shape&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when I try to create a new rectangle, I can use the &lt;code&gt;Rectangle&lt;/code&gt; type to
ensure that I provided all the required properties:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rect&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Rectangle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can play around with these types in
&lt;a href=&quot;https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgMoAs4AcUG8BQyRy6EwA5umAPwBcyIArgLYBG0A3IcQO7AAmYdHQYt2ULgF98+MAE8cyAEoQEYOCHIAbFAF5lEAI6NgUCPwA8GbBAB8MhAHsQAZzDIza+irUbte5AJiEjJKMHoAFgAabiI+QXR6AA58SSA&quot;&gt;this TypeScript playground&lt;/a&gt;,
and
&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/utility-types.html&quot;&gt;read more about Utility types&lt;/a&gt;
on the TypeScript website.&lt;/p&gt;
&lt;p&gt;Happy requiring!&lt;/p&gt;
</description>
      <pubDate>Sat, 19 Dec 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/make-all-properties-required-in-typescript/</guid>
    </item>
    <item>
      <title>Add text to the beginning of every file</title>
      <link>https://seanmcp.com/articles/add-text-to-the-beginning-of-every-file/</link>
      <description>&lt;p&gt;While converting a JavaScript &lt;code&gt;create-react-app&lt;/code&gt; project to TypeScript, I wanted
a single line of text to every &lt;code&gt;.tsx&lt;/code&gt; file. Searching for an answer brought me
to
&lt;a href=&quot;https://superuser.com/questions/246837/how-do-i-add-text-to-the-beginning-of-a-file-in-bash&quot;&gt;this question on StackExchange&lt;/a&gt;,
specifically &lt;a href=&quot;https://superuser.com/a/521654&quot;&gt;this answer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;echo&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt;, you can add new text to the old file&#39;s contents and send
it to the original file. Combined with a &lt;code&gt;for&lt;/code&gt; loop to iterate over the matching
files, I came up with a one-liner&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/add-text-to-the-beginning-of-every-file/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; that saved me a lot of time:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; **/*.tsx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;// @ts-nocheck
&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$f&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$f&lt;/span&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script looks for all &lt;code&gt;.tsx&lt;/code&gt; files in any directory, then adds
&lt;code&gt;// @ts-nocheck&lt;/code&gt; and a newline to the beginning of the file. But there is
nothing magic about the selector or added text; you can use whatever you want
for those values.&lt;/p&gt;
&lt;p&gt;Hope that saves you a bit of time too!&lt;/p&gt;
&lt;p&gt;Happy scripting!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Okay, with the newline it&#39;s kind of a two-liner, but you can copy and paste
it directly into the command line. &lt;a href=&quot;https://seanmcp.com/articles/add-text-to-the-beginning-of-every-file/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Fri, 18 Dec 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/add-text-to-the-beginning-of-every-file/</guid>
    </item>
    <item>
      <title>Sass converts hsla to hex incorrectly</title>
      <link>https://seanmcp.com/articles/sass-converts-hsla-to-hex-incorrectly/</link>
      <description>&lt;p&gt;I ran into an issue where Sass was converting &lt;code&gt;hsla()&lt;/code&gt; values to hex
incorrectly. It would take an input like this:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* input.scss */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.subtle-blue&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsla&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;212&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 10%&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And convert it into:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* output.css */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.subtle-blue&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #407bbf&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is &lt;strong&gt;not&lt;/strong&gt; the same color. When processing the input styles, Sass ignores
the alpha (opacity) value and converts it into a standard hex.&lt;/p&gt;
&lt;p&gt;You can see the different between the two values here:&lt;/p&gt;
&lt;style&gt;
.exs {
    display: grid;
    gap: 0.5rem;
    grid-template-columns: repeat(2, 1fr);
    margin: 2rem 0;
}
.ex {
    padding: 4rem 0.5rem 0.5rem;
}
.ex code {
    background-color: black !important;
    color: white !important;
    padding: 2px 4px;
}
&lt;/style&gt;
&lt;div class=&quot;exs&quot;&gt;
    &lt;div class=&quot;ex&quot; style=&quot;background-color:hsla(212, 50%, 50%, 10%)&quot;&gt;
        &lt;code&gt;hsla(212, 50%, 50%, 10%)&lt;/code&gt;
    &lt;/div&gt;
    &lt;div class=&quot;ex&quot; style=&quot;background-color:#407bbf;&quot;&gt;
        &lt;code&gt;#407bbf&lt;/code&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you search around for an answer, you will find a few suggestions to
&lt;a href=&quot;https://github.com/sass/sass/issues/469#issuecomment-461675216&quot;&gt;use strings for &lt;code&gt;hsl&lt;/code&gt; values&lt;/a&gt;
or
&lt;a href=&quot;https://github.com/sass/sass/issues/469#issuecomment-77290544&quot;&gt;recreating the &lt;code&gt;hsl&lt;/code&gt; and &lt;code&gt;hsla&lt;/code&gt; functions in Sass&lt;/a&gt;.
Neither of those seemed an idea solution.&lt;/p&gt;
&lt;p&gt;Instead of changing how you declare &lt;code&gt;hsl&lt;/code&gt; value or recreating the function, you
can fix this issue by &lt;strong&gt;using decimal alpha values instead of percent&lt;/strong&gt;. Going
back to the original example, change &lt;code&gt;10%&lt;/code&gt; to &lt;code&gt;0.1&lt;/code&gt;:&lt;/p&gt;
&lt;!-- ```css/2 --&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Input Sass */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.subtle-blue&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hsla&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;212&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And Sass will convert it to alpha-supporting &lt;code&gt;rgba&lt;/code&gt;:&lt;/p&gt;
&lt;!-- ```css/2 --&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Output css */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;.subtle-blue&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;64&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 123&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 191&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 0.1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These values aren&#39;t identical because
&lt;a href=&quot;https://stackoverflow.com/questions/31613667/hsl-to-rgb-conversion-math&quot;&gt;math is required&lt;/a&gt;,
but they&#39;re infinitely closer than the non-alpha hex value:&lt;/p&gt;
&lt;div class=&quot;exs&quot;&gt;
    &lt;div class=&quot;ex&quot; style=&quot;background-color:hsla(212, 50%, 50%, 0.1)&quot;&gt;
        &lt;code&gt;hsla(212, 50%, 50%, 0.1)&lt;/code&gt;
    &lt;/div&gt;
    &lt;div class=&quot;ex&quot; style=&quot;background-color:rgba(64, 123, 191, 0.1);&quot;&gt;
        &lt;code&gt;rgba(64, 123, 191, 0.1)&lt;/code&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can see this behavior for yourself in
&lt;a href=&quot;https://sass.js.org/&quot;&gt;this Sass playground&lt;/a&gt; but not in
&lt;a href=&quot;https://www.sassmeister.com/&quot;&gt;Sassmeister&lt;/a&gt;. So it may depend on the flavor and
version of Sass that you are using.&lt;/p&gt;
&lt;p&gt;But for a quick fix that doesn&#39;t involve wading into the release notes of your
dependencies, opt for decimal alpha values in &lt;code&gt;hsla&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Happy styling!&lt;/p&gt;
</description>
      <pubDate>Thu, 17 Dec 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/sass-converts-hsla-to-hex-incorrectly/</guid>
    </item>
    <item>
      <title>Increase the playback speed on any audio or video online</title>
      <link>https://seanmcp.com/articles/increase-the-playback-speed-on-any-audio-or-video-online/</link>
      <description>&lt;p&gt;I like learning from audio and video, from podcasts to YouTube videos. My
favorite applications let you alter the playback speed of the audio and video so
that you can consume the content faster (or slower).&lt;/p&gt;
&lt;p&gt;I find this particularly useful for unscripted podcasts or coding videos and
will usually increase the speed to 2x (or more). At that rate, I can get through
a 60 minute podcast in half the time!&lt;/p&gt;
&lt;p&gt;However, I sometimes find myself on websites where they do not allow you to
change the playback speed. Recently I was watching a coding tutorial on Vimeo
and was stuck at the normal speed. Not a good use of my time.&lt;/p&gt;
&lt;p&gt;Since online audio and video are played through native HTML elements, we have
the ability to customize their behavior with the developer console.&lt;/p&gt;
&lt;p&gt;First &lt;a href=&quot;https://seanmcp.com/articles/increase-the-playback-speed-on-any-audio-or-video-online/how-to-open-dev-tools&quot;&gt;open the dev tools with your favorite method&lt;/a&gt;,
and click on the &amp;quot;Console&amp;quot; tab. Then enter and run the following script&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/increase-the-playback-speed-on-any-audio-or-video-online/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;audio,video&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;playbackRate &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This grabs all of the &lt;code&gt;audio&lt;/code&gt; and &lt;code&gt;video&lt;/code&gt; elements from the DOM, loops over each
node, and sets the playback rate to &lt;code&gt;2.0&lt;/code&gt; or 2x. If you prefer a different rate,
you will only need to edit that last number.&lt;/p&gt;
&lt;p&gt;If you are working on an application that plays audio or video, make sure to
give the user the ability to change the playback rate. That way everyone can
listen at the speed that is best for them&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/increase-the-playback-speed-on-any-audio-or-video-online/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Happy listening/watching!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/tools/chrome-devtools/console/utilities#queryselectorall&quot;&gt;&lt;code&gt;$$&lt;/code&gt; is a shorthand for &lt;code&gt;document.querySelectorAll()&lt;/code&gt;&lt;/a&gt;
and works in all modern browsers &lt;a href=&quot;https://seanmcp.com/articles/increase-the-playback-speed-on-any-audio-or-video-online/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;For some light reading on the subject, checkout
&lt;a href=&quot;https://homes.cs.washington.edu/~reinecke//Publications_files/Bragg_CHI2018.pdf&quot;&gt;this paper on &lt;em&gt;Human Listening Rates&lt;/em&gt;&lt;/a&gt;
by the University of Washington CS department &lt;a href=&quot;https://seanmcp.com/articles/increase-the-playback-speed-on-any-audio-or-video-online/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Tue, 15 Dec 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/increase-the-playback-speed-on-any-audio-or-video-online/</guid>
    </item>
    <item>
      <title>Standardize character width with CSS</title>
      <link>https://seanmcp.com/articles/standardize-character-width-with-css/</link>
      <description>&lt;p&gt;&lt;strong&gt;Authors note&lt;/strong&gt;: Before you read this article, you will want to click the
&amp;quot;Start timer&amp;quot; button below to enable the live demos. You can cancel it at any
time by clicking &amp;quot;Stop timer&amp;quot;.&lt;/p&gt;
&lt;div class=&quot;button-container&quot;&gt;
    &lt;button onclick=&quot;startTimer()&quot;&gt;Start timer&lt;/button&gt;
    &lt;button onclick=&quot;stopTimer()&quot;&gt;Stop timer&lt;/button&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;p&gt;The width of a character is the amount of horizontal space that it occupies.
This width varies between characters, weights, and typefaces. In Lato, for
example, the letter &lt;strong&gt;W&lt;/strong&gt; is wider than the letter &lt;strong&gt;I&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For most use cases, the varied width of characters isn&#39;t an issue. However, when
you are creating an component like a timer, the differences in width can produce
some undesirable movements as the numbers change.&lt;/p&gt;
&lt;p&gt;Take a look at this example when timer running. Since the characters are all
different widths, the number &amp;quot;jitters&amp;quot; around as it increments:&lt;/p&gt;
&lt;div aria-label=&quot;Default&quot; class=&quot;example&quot;&gt;
    &lt;span class=&quot;count&quot;&gt;0&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;This isn&#39;t the end of the world, but it&#39;s not preferable.&lt;/p&gt;
&lt;p&gt;To alleviate this, I have in the past turned to monospace typefaces. These
allocate the same width for each character, regardless of the space that the
stroke needs.&lt;/p&gt;
&lt;p&gt;In this example, we can see that the jittering is resolved and the timer
increments smoothly:&lt;/p&gt;
&lt;div aria-label=&quot;Monospaced&quot; class=&quot;example&quot;&gt;
    &lt;span class=&quot;count&quot;&gt;0&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;However, altering the typeface might not be the best solution for your product.
Especially when the change was only made to prevent the jittering.&lt;/p&gt;
&lt;p&gt;Instead, we can use two CSS properties&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/standardize-character-width-with-css/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; to standardize the character width of
an element:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.standardize-character-width&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-feature-settings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tnum&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-variant-numeric&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; tabular-nums&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With those two in place, we can preserve the original typeface and avoid visual
jittering:&lt;/p&gt;
&lt;div aria-label=&quot;Standardized&quot; class=&quot;example&quot;&gt;
    &lt;span class=&quot;count&quot;&gt;0&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;A few things to note:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Adding these properties changes the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Letter-spacing&quot;&gt;tracking&lt;/a&gt;, or letter spacing,
of the characters. This is necessary to standardize widths but might be
undesirable for typography aficionados.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-variant-numeric&lt;/code&gt; does not work in Internet Explorer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-feature-settings&lt;/code&gt; supports IE but only works with
&lt;a href=&quot;https://en.wikipedia.org/wiki/OpenType&quot;&gt;OpenType fonts&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That being said, this is CSS progressive enhancement: for whom it works, it
improves the experience. I&#39;m pretty happy with this solution, and I have used it
in production with
&lt;a href=&quot;https://seanmcp.github.io/contractions&quot;&gt;Contraction Tracker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more information about the CSS properties, you can read about
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/font-feature-settings&quot;&gt;&lt;code&gt;font-feature-settings&lt;/code&gt;&lt;/a&gt;
and
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant-numeric&quot;&gt;&lt;code&gt;font-variant-numetric&lt;/code&gt;&lt;/a&gt;
on MDN.&lt;/p&gt;
&lt;p&gt;Happy standardizing!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I first saw this solution from
&lt;a href=&quot;https://twitter.com/sulco/status/1293862293139337217&quot;&gt;Tomek Sułkowski (@sulco) on Twitter&lt;/a&gt;.
He shares lots of great tips like this and is worth the follow. &lt;a href=&quot;https://seanmcp.com/articles/standardize-character-width-with-css/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Wed, 09 Dec 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/standardize-character-width-with-css/</guid>
    </item>
    <item>
      <title>See all package versions in npm cli</title>
      <link>https://seanmcp.com/articles/see-all-package-versions-in-npm-cli/</link>
      <description>&lt;p&gt;At work, I ran into an issue that may have been related to an external
dependency. I wanted to update the package to see if a future release fixed the
issue.&lt;/p&gt;
&lt;p&gt;To get the latest version of a package, you can use the &lt;code&gt;@latest&lt;/code&gt; tag:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; i package-name@latest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what if you need the next most recent release? Or five versions ago? I
wanted to see a list of published versions without having to leave the command
line.&lt;/p&gt;
&lt;p&gt;A quick search led me to
&lt;a href=&quot;https://willi.am/blog/2015/07/17/viewing-all-versions-of-an-npm-package-including-pre-release/&quot;&gt;&lt;em&gt;Viewing All Versions of an NPM Package (Including Pre-Release)&lt;/em&gt;&lt;/a&gt;
by Will Anderson. He pointed to the &lt;code&gt;npm view&lt;/code&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/see-all-package-versions-in-npm-cli/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; command and illustrated how
to use it:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; view package-name versions&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will print all of the published versions of any package on the registry.
Pretty handy!&lt;/p&gt;
&lt;p&gt;Anderson mentions that this was undocumented in 2015, but today we have
&lt;a href=&quot;https://docs.npmjs.com/cli/v6/commands/npm-view&quot;&gt;a page dedicated to the &lt;code&gt;view&lt;/code&gt; command on npm&lt;/a&gt;.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Anderson used the alias &lt;code&gt;npm show&lt;/code&gt; &lt;a href=&quot;https://seanmcp.com/articles/see-all-package-versions-in-npm-cli/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Wed, 09 Dec 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/see-all-package-versions-in-npm-cli/</guid>
    </item>
    <item>
      <title>TypeScript without TypeScript</title>
      <link>https://seanmcp.com/articles/typescript-without-typescript/</link>
      <description>&lt;p&gt;As a superset of JavaScript, TypeScript provides a lot of useful features. It&#39;s
no mystery why it is one of the
&lt;a href=&quot;https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-languages-loved&quot;&gt;&amp;quot;most loved&amp;quot; languages in software engineering&lt;/a&gt;.
When everything is running smoothly, TypeScript can been a huge boon to
productivity.&lt;/p&gt;
&lt;p&gt;However, therein lies one of TypeScript&#39;s weaknesses: the setup. TS adds a level
of overhead that is, in my opinion, prohibitively complex for most of my
projects. So while I would love the benefits of working in TypeScript, I don&#39;t
want to go through the trouble of setting it up.&lt;/p&gt;
&lt;p&gt;In searching for a solution to my problem, I came across
&lt;a href=&quot;https://fettblog.eu/typescript-jsdoc-superpowers/&quot;&gt;&lt;em&gt;TypeScript without TypeScript -- JSDoc superpowers&lt;/em&gt;&lt;/a&gt;
by &lt;a href=&quot;https://twitter.com//ddprrt&quot;&gt;@ddprrt&lt;/a&gt; on &lt;a href=&quot;http://fettblog.eu&quot;&gt;fettblog.eu&lt;/a&gt;. In it, the author
highlights how &lt;a href=&quot;https://jsdoc.app/&quot;&gt;JSDoc&lt;/a&gt; can provide some of the features of
TypeScript without the setup.&lt;/p&gt;
&lt;p&gt;I found the
&lt;a href=&quot;https://fettblog.eu/typescript-jsdoc-superpowers/#defining-objects&quot;&gt;&amp;quot;Defining Objects&amp;quot; section&lt;/a&gt;
to be particularly helpful. The ability to create &amp;quot;interfaces&amp;quot; for functions and
objects in JavaScript is really powerful. If you combine that with
&lt;a href=&quot;https://code.visualstudio.com/docs/nodejs/working-with-javascript#_type-checking-javascript&quot;&gt;&lt;code&gt;// @ts-check&lt;/code&gt;&lt;/a&gt;
and a TS-centric IDE like VS Code, you&#39;ll find yourself in a great position when
developing.&lt;/p&gt;
&lt;p&gt;Give the article a read and &lt;a href=&quot;https://seanmcp.com/articles/typescript-without-typescript/#comment-link&quot;&gt;let me know what you think&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy typing!&lt;/p&gt;
</description>
      <pubDate>Tue, 08 Dec 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/typescript-without-typescript/</guid>
    </item>
    <item>
      <title>Emulate iPhone &amp; iPad in Safari</title>
      <link>https://seanmcp.com/articles/emulate-iphone-and-ipad-in-safari/</link>
      <description>&lt;p&gt;To emulate an iPhone or iPad in Safari, you first need to have
&lt;a href=&quot;https://support.apple.com/guide/safari/use-the-developer-tools-in-the-develop-menu-sfri20948/mac&quot;&gt;the developer tools enabled&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then when visiting a page that you want to test, select &amp;quot;Develop&amp;quot; in the
application toolbar then &amp;quot;Enter Responsive Design Mode&amp;quot;.&lt;/p&gt;
&lt;p&gt;This will open a special window where you can emulate your website on an array
of Apple devices and user agents.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/safari-responsive-design-mode.png&quot; alt=&quot;Viewing SeanMcP.com on an iPad mini in Safari&#39;s responsive design mode&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;keyboard-shortcut&quot; tabindex=&quot;-1&quot;&gt;Keyboard shortcut&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/emulate-iphone-and-ipad-in-safari/#keyboard-shortcut&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Keyboard shortcut”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;To enter Responsive Design Mode without going through the toolbar, you can use
the shortcut &lt;kbd&gt;control&lt;/kbd&gt; &lt;kbd&gt;command&lt;/kbd&gt; &lt;kbd&gt;r&lt;/kbd&gt;.&lt;/p&gt;
&lt;p&gt;Happy emulating!&lt;/p&gt;
</description>
      <pubDate>Wed, 02 Sep 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/emulate-iphone-and-ipad-in-safari/</guid>
    </item>
    <item>
      <title>Make a POST request with fetch</title>
      <link>https://seanmcp.com/articles/make-a-post-request-with-fetch/</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API&quot;&gt;&lt;code&gt;fetch&lt;/code&gt; is utility for making HTTP requests&lt;/a&gt;
from the browser. It is
&lt;a href=&quot;https://caniuse.com/#feat=fetch&quot;&gt;available in all modern browsers&lt;/a&gt; and has a
&lt;a href=&quot;https://github.com/github/fetch&quot;&gt;popular polyfill for older browsers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To make a &lt;code&gt;GET&lt;/code&gt; request, just pass the endpoint to the global &lt;code&gt;fetch&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://mirror-api.seanmcp.repl.co/get&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It returns a promise that will resolve with the server response. From there, you
can convert the response to JSON and read the value in your code:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://mirror-api.seanmcp.repl.co/get&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But &lt;code&gt;fetch&lt;/code&gt; also handles other request methods. After &lt;code&gt;GET&lt;/code&gt;, the first you will
reach for is &lt;code&gt;POST&lt;/code&gt;. But it isn&#39;t immediately apparent how to make a request
with a different method.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;how-to-post-with-fetch&quot; tabindex=&quot;-1&quot;&gt;How to &lt;code&gt;POST&lt;/code&gt; with &lt;code&gt;fetch&lt;/code&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/make-a-post-request-with-fetch/#how-to-post-with-fetch&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “How to POST with fetch”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The global &lt;code&gt;fetch&lt;/code&gt; function accepts a second options argument. There you can set
the method, add a body, and set headers.&lt;/p&gt;
&lt;p&gt;Here is an example POST request that sends a JSON body:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://mirror-api.seanmcp.repl.co/post&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello API!&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you have the request in order, you can handle the promises and get the
server response.&lt;/p&gt;
&lt;p&gt;For more information on the available including examples with other methods,
checkout
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch&quot;&gt;&lt;em&gt;Using Fetch&lt;/em&gt; on MDN&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy fetching!&lt;/p&gt;
</description>
      <pubDate>Fri, 07 Aug 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/make-a-post-request-with-fetch/</guid>
    </item>
    <item>
      <title>Remove an item at a given index in JavaScript</title>
      <link>https://seanmcp.com/articles/remove-an-item-at-a-given-index-in-javascript/</link>
      <description>&lt;p&gt;Removing an item from an array at a given index is a pretty common task in
programming. So it is a little disappointing that the Array prototype in
JavaScript doesn&#39;t have a method for that exact task.&lt;/p&gt;
&lt;p&gt;If you search for an answer, you&#39;ll find solutions that use &lt;code&gt;Array#slice&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;removeAtWithSlice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And answers with &lt;code&gt;Array#splice&lt;/code&gt; (which mutates the original array):&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;removeAtWithSplice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; copy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  copy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;splice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; copy&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both of these require that you remember the difference between the two methods,
their behavior, and the arguments they require.&lt;/p&gt;
&lt;p&gt;Personally, neither of these solutions are memorable, so I often find myself
searching &amp;quot;how to remove an item at a given index JS&amp;quot;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;filtering&quot; tabindex=&quot;-1&quot;&gt;Filtering&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-an-item-at-a-given-index-in-javascript/#filtering&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Filtering”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Instead of using &lt;code&gt;slice&lt;/code&gt;/&lt;code&gt;splice&lt;/code&gt;, I came upon a new method that is my favorite
yet: &lt;code&gt;Array#filter&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;filter&lt;/code&gt; method will iterate over your array and return a new one with
values that pass a certain criterion. You have probably used &lt;code&gt;Array#filter&lt;/code&gt; for
a todo-like example before:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; done &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; todos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;todo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; todo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isComplete &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Like other array methods, you also have access to the current index as a
parameter. So to use &lt;code&gt;Array#filter&lt;/code&gt; to remove an item from an array, check if
the indices match:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;removeAtWithFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I&#39;m using the &lt;code&gt;_&lt;/code&gt; to indicate a parameter that I don&#39;t intend to
reference and a non-description &lt;code&gt;i&lt;/code&gt; variable because &lt;code&gt;index&lt;/code&gt; is already in
scope.&lt;/p&gt;
&lt;p&gt;As I mentioned above, this is now my preferred method of removing an item from
an array. I am more familiar with &lt;code&gt;Array#filter&lt;/code&gt; and the idea of &amp;quot;filtering out&amp;quot;
in the unwanted index makes sense. The other two methods are harder for me to
conceptualize.&lt;/p&gt;
&lt;p&gt;There are two objective benefits to this method as well. First, it doesn&#39;t
mutate the array (unlike &lt;code&gt;Array#splice&lt;/code&gt;), which allows for functional
programming without an additional step. And second, it only iterates the length
of the array once (vs a potential two iterations for &lt;code&gt;Array#slice&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;For all those reasons, I recommend you use &lt;code&gt;Array#filter&lt;/code&gt; for removing an item
from an array at a given index in JavaScript. Let me know if you have an even
better method; I&#39;d love to hear it!&lt;/p&gt;
&lt;p&gt;Happy filtering!&lt;/p&gt;
</description>
      <pubDate>Wed, 05 Aug 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/remove-an-item-at-a-given-index-in-javascript/</guid>
    </item>
    <item>
      <title>Tab focus not working in Safari?</title>
      <link>https://seanmcp.com/articles/tab-focus-not-working-in-safari/</link>
      <description>&lt;p&gt;While doing some cross-browser testing in Safari, I noted that &lt;kbd&gt;tab&lt;/kbd&gt;
was not working as expected. I was looking at a focus-managed component, so my
first thought was that I had done something in my JavaScript that did not work
in Safari.&lt;/p&gt;
&lt;p&gt;After trying to debug the issue for a few minutes, I finally noticed that
&lt;strong&gt;&lt;kbd&gt;tab&lt;/kbd&gt; wasn&#39;t working anywhere&lt;/strong&gt;, not just my component. This was both
a relief (it wasn&#39;t me!) and a mystery. How could tab not work?&lt;/p&gt;
&lt;p&gt;A quick Google search for &amp;quot;Safari tab order&amp;quot; lead me to this StackOverflow
question and answer:
&lt;a href=&quot;https://stackoverflow.com/questions/1848390/safari-ignoring-tabindex&quot;&gt;&lt;em&gt;Safari ignoring tabindex&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As it turns out, Safari does not enable tab highlighting by default. To turn it
on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &amp;quot;Preferences&amp;quot;&lt;/li&gt;
&lt;li&gt;Select the &amp;quot;Advanced&amp;quot; tab&lt;/li&gt;
&lt;li&gt;Check &amp;quot;Press Tab to highlight each item on a webpage&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With that setting enabled, &lt;kbd&gt;tab&lt;/kbd&gt; worked as I expected.
&lt;a href=&quot;https://stackoverflow.com/a/1914496/8486161&quot;&gt;Thanks &lt;code&gt;graphicdivine&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;While you&#39;re fiddling with settings, the A11y Project has a guide for
&lt;a href=&quot;https://www.a11yproject.com/posts/2017-12-29-macos-browser-keyboard-navigation/&quot;&gt;enabling browser keyboard navigation on macOS&lt;/a&gt;
that is worth checking out.&lt;/p&gt;
&lt;p&gt;Setting you computer up for accessibility testing makes it that much easier to
ensure that you&#39;re building a product that will work for everyone.&lt;/p&gt;
&lt;p&gt;Happy tabbing!&lt;/p&gt;
</description>
      <pubDate>Tue, 04 Aug 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/tab-focus-not-working-in-safari/</guid>
    </item>
    <item>
      <title>Fix &#39;EMFILE: too many open files&#39; error in Jest</title>
      <link>https://seanmcp.com/articles/fix-emfile-too-many-open-files-error-in-jest/</link>
      <description>&lt;p&gt;When I tried to run &lt;code&gt;jest --watch&lt;/code&gt; in a codebase, I received the following
error:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;Error: EMFILE: too many &lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt; files, &lt;span class=&quot;token function&quot;&gt;watch&lt;/span&gt;
    at FSEvent.FSWatcher._handle.onchange &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs.js:1372:28&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
Emitted &lt;span class=&quot;token string&quot;&gt;&#39;error&#39;&lt;/span&gt; event at:
    at NodeWatcher.checkedEmitError &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;/Users/seanmcp/dev/REPO/node_modules/sane/src/node_watcher.js:143:12&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    at FSWatcher.emit &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;events.js:182:13&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    at FSEvent.FSWatcher._handle.onchange &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs.js:1378:12&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A Google search of the error message produced three (!) results.
&lt;a href=&quot;https://buildmedia.readthedocs.org/media/pdf/delivery-console/stable/delivery-console.pdf&quot;&gt;The second was a PDF from Mozilla&lt;/a&gt;
that recommended installing &lt;a href=&quot;https://facebook.github.io/watchman/&quot;&gt;&lt;code&gt;watchman&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;why-watchman%3F&quot; tabindex=&quot;-1&quot;&gt;Why &lt;code&gt;watchman&lt;/code&gt;?&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/fix-emfile-too-many-open-files-error-in-jest/#why-watchman%3F&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Why watchman?”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Watchman is a file-watching service from Facebook that will respond to changes
in your files. Jest (also by Facebook)
&lt;a href=&quot;https://jestjs.io/docs/en/cli#--watchman&quot;&gt;default to using watchman in &lt;code&gt;--watch&lt;/code&gt; mode&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://facebook.github.io/watchman/docs/install.html&quot;&gt;Watchman is available on all major platforms&lt;/a&gt;.
On a Mac or Linux with Homebrew installed, you can run:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; watchman&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that installed, Jest&#39;s &lt;code&gt;--watch&lt;/code&gt; flag works as expected.&lt;/p&gt;
&lt;p&gt;I hope that works for you (and saves you some valuable time)!&lt;/p&gt;
&lt;p&gt;Happy testing!&lt;/p&gt;
</description>
      <pubDate>Wed, 29 Jul 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/fix-emfile-too-many-open-files-error-in-jest/</guid>
    </item>
    <item>
      <title>Updated TypeScript mega-course on Egghead.io</title>
      <link>https://seanmcp.com/articles/updated-typescript-mega-course-on-egghead/</link>
      <description>&lt;p&gt;&lt;a href=&quot;https://seanmcp.com/articles/updated-typescript-mega-course-on-egghead/typescript-mega-course-on-egghead&quot;&gt;Last month, I embarked on a journey to learn TypeScript better&lt;/a&gt;.
I hand-crafted a TypeScript&amp;quot;mega-course&amp;quot; on &lt;a href=&quot;http://Egghead.io&quot;&gt;Egghead.io&lt;/a&gt; by cobbling multiple
courses into one.&lt;/p&gt;
&lt;p&gt;My goal was to complete the course in three weeks. Now a month and a half later,
I have completed the course and am ready to reflect on my experience.&lt;/p&gt;
&lt;p&gt;Overall, it was a beneficial experience. I learned a lot more about types and
how to write meaningful generics that will help make my code more reusable.&lt;/p&gt;
&lt;p&gt;I also gained a greater appreciation for TypeScript as a language. There were
some examples where I needed to stop the video and try to read what was
happened. I know TS is technically a super-set of JavaScript, but it is 100% a
proficiency of its own.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;updated-mega-course&quot; tabindex=&quot;-1&quot;&gt;Updated Mega-course&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/updated-typescript-mega-course-on-egghead/#updated-mega-course&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Updated Mega-course”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;After completing the course, I want to update and annotate the original
syllabus. Here is the updated course playlist:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Optional:
&lt;a href=&quot;https://egghead.io/courses/up-and-running-with-typescript&quot;&gt;&lt;em&gt;Up and Running with TypeScript&lt;/em&gt;&lt;/a&gt;
by John Lindquist (22 min)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;This was helpful, but very basic. Consider skipping this if you already know
how to set up a TypeScript project&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://egghead.io/courses/use-types-effectively-in-typescript&quot;&gt;&lt;em&gt;Use Types Effectively in TypeScript&lt;/em&gt;&lt;/a&gt;
by Ari Picker (29 min)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;This was a great introduction into TypeScript on its own. I learned a lot
about generics, which are an important feature.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://egghead.io/courses/practical-advanced-typescript&quot;&gt;&lt;em&gt;Practical Advanced TypeScript&lt;/em&gt;&lt;/a&gt;
by Rares Matei (62 min)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;I took more notes on this course than any of the others. This was definitely
the material I needed to introduce me to more advanced TypeScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://egghead.io/courses/advanced-static-types-in-typescript&quot;&gt;&lt;em&gt;Advanced Static Types in TypeScript&lt;/em&gt;&lt;/a&gt;
by Marius Schulz (67 min)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;There was some overlap between this course and the previous, but they both did
a good job of explaining core type concepts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The updated runtime is 2 hours and 38 minutes to 3 hours, depending on whether
you include the optional introduction.&lt;/p&gt;
&lt;p&gt;It also drops both of Basarat Ali Syed&#39;s courses, &lt;em&gt;Async/Await using TypeScript&lt;/em&gt;
and &lt;em&gt;Use Typescript to develop React Applications&lt;/em&gt;. Both were fine but
ultimately weren&#39;t substantial enough to be included in the mega-course.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I hope that was helpful! Let me know if you take this TypeScript &amp;quot;mega-course&amp;quot;
on &lt;a href=&quot;http://Egghead.io&quot;&gt;Egghead.io&lt;/a&gt; and what you think about it.&lt;/p&gt;
&lt;p&gt;Happy learning!&lt;/p&gt;
</description>
      <pubDate>Mon, 27 Jul 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/updated-typescript-mega-course-on-egghead/</guid>
    </item>
    <item>
      <title>Access the home directory in Deno</title>
      <link>https://seanmcp.com/articles/access-the-home-directory-in-deno/</link>
      <description>&lt;p&gt;If you want to access the home directory from you Deno program, you can use the
&lt;code&gt;Deno.env&lt;/code&gt;&#39;s &lt;code&gt;get&lt;/code&gt; method with &lt;code&gt;&amp;quot;HOME&amp;quot;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;HOME&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In unix environments, returns a string along the lines of &lt;code&gt;&amp;quot;/home/USER&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So if you want to write a script that accesses a configuration file like
&lt;code&gt;.bashrc&lt;/code&gt;, you could read the file with:&lt;/p&gt;
&lt;!-- ```js/2 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// read-bashrc.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bashConfig &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readTextFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;HOME&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/.bashrc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we are accessing &lt;code&gt;Deno.env&lt;/code&gt;, we need to run the program with the &lt;code&gt;env&lt;/code&gt;
permission:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;deno run --allow-env read-bashrc.ts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is a Repl where you can
&lt;a href=&quot;https://repl.it/@SeanMcP/deno-access-home-directory&quot;&gt;play around with accessing the home directory in Deno&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Fri, 17 Jul 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/access-the-home-directory-in-deno/</guid>
    </item>
    <item>
      <title>Before You Debug</title>
      <link>https://seanmcp.com/articles/before-you-debug/</link>
      <description>&lt;p&gt;Debugging, &amp;quot;the process of finding and resolving defects within a computer
system&amp;quot;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/before-you-debug/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, is a critical skill for software development. It&#39;s how we figure
out what went wrong and how to fix it.&lt;/p&gt;
&lt;p&gt;This can be as informal as throwing &lt;code&gt;* { outline: 1px solid red }&lt;/code&gt; on all your
elements or sophisticated as using an IDE&#39;s debugger.&lt;/p&gt;
&lt;p&gt;But whatever your method, there are certain steps that you can follow to help
yourself debug more logically and efficiently.&lt;/p&gt;
&lt;p&gt;This garden aims to detail everything you should do &lt;em&gt;before you actually start
debugging&lt;/em&gt;. Think of this as the prep work before you start cooking.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;pre-steps&quot; tabindex=&quot;-1&quot;&gt;Pre-steps&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/before-you-debug/#pre-steps&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Pre-steps”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Relax&lt;/strong&gt;: Find a bug can be frustrating, and those emotions can impede the
debugging process. Take a deep breath and dive in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Describe what happened&lt;/strong&gt;: Did the process exit? Did the page fail to
render? Is there a message in the console? Does the UI not respond correctly?
Understanding what happened is the first step to solving a problem. The &amp;quot;how&amp;quot;
comes later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read the error message&lt;/strong&gt;: Most errors will provide you useful information
in the message. Some APIs provide a detailed explanation of what went wrong.
So take the time and read it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Follow the stack trace&lt;/strong&gt;: If the error includes a stack, walk through each
line. Where did the error originate? What it internal or external code?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pinpoint the error&lt;/strong&gt;: Try to isolate the exact point where something went
wrong. In the stack trace, this will usually have a file name and a line
number, &lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;app.js:25&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspect the line&lt;/strong&gt;: Read the entire line where the error occurred. Is there
anything that immediately jumps out to you? Sometimes the bug could be as
simple as a typo or an unexpected type.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review the block&lt;/strong&gt;: Follow the block from start to finish, making note of
the line in question. Try to get a good sense of how that code is working.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scan any higher scopes&lt;/strong&gt;: Make sure you understand at a high-level what the
code is doing and what variables are needed/expected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make a hypothesis&lt;/strong&gt;: You are a scientist, after all. Make an educated guess
about what went wrong and what will fix it. Make sure to review your
hypothesis while you&#39;re debugging.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;note&quot; tabindex=&quot;-1&quot;&gt;Note&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/before-you-debug/#note&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Note”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;This is a living document and will change as my approach to debugging grows over
time. If you have any suggestions, &lt;a href=&quot;https://seanmcp.com/articles/before-you-debug/#comment-link&quot;&gt;please let me know&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;additional-reading&quot; tabindex=&quot;-1&quot;&gt;Additional reading&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/before-you-debug/#additional-reading&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Additional reading”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jvns.ca/blog/debugging-attitude-matters/&quot;&gt;&lt;em&gt;When debugging, your attitude matters&lt;/em&gt;&lt;/a&gt;
by Julia Evans&lt;/li&gt;
&lt;/ul&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Debugging&quot;&gt;https://en.wikipedia.org/wiki/Debugging&lt;/a&gt; &lt;a href=&quot;https://seanmcp.com/articles/before-you-debug/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Fri, 10 Jul 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/before-you-debug/</guid>
    </item>
    <item>
      <title>Before Debugging</title>
      <link>https://seanmcp.com/articles/before-debugging/</link>
      <description>&lt;p&gt;Debugging, &amp;quot;the process of finding and resolving defects within a computer
system&amp;quot;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/before-debugging/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, is a critical skill for software development. It&#39;s how we figure
out what went wrong and how to fix it.&lt;/p&gt;
&lt;p&gt;This can be as informal as throwing &lt;code&gt;* { outline: 1px solid red }&lt;/code&gt; on all your
elements or sophisticated as using an IDE&#39;s debugger.&lt;/p&gt;
&lt;p&gt;But whatever your method, there are certain steps that you can follow to help
yourself debug more logically and efficiently.&lt;/p&gt;
&lt;p&gt;This garden aims to detail everything you should do &lt;em&gt;before you actually start
debugging&lt;/em&gt;. Think of this as the prep work before you start cooking.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;pre-steps&quot; tabindex=&quot;-1&quot;&gt;Pre-steps&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/before-debugging/#pre-steps&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Pre-steps”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Relax&lt;/strong&gt;: Find a bug can be frustrating, and those emotions can impede the
debugging process. Take a deep breath and dive in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Describe what happened&lt;/strong&gt;: Did the process exit? Did the page fail to
render? Is there a message in the console? Does the UI not respond correctly?
Understanding what happened is the first step to solving a problem. The &amp;quot;how&amp;quot;
comes later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read the error message&lt;/strong&gt;: Most errors will provide you useful information
in the message. Some APIs provide a detailed explanation of what went wrong.
So take the time and read it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Follow the stack trace&lt;/strong&gt;: If the error includes a stack, walk through each
line. Where did the error originate? What it internal or external code?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pinpoint the error&lt;/strong&gt;: Try to isolate the exact point where something went
wrong. In the stack trace, this will usually have a file name and a line
number, &lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;app.js:25&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inspect the line&lt;/strong&gt;: Read the entire line where the error occurred. Is there
anything that immediately jumps out to you? Sometimes the bug could be as
simple as a typo or an unexpected type.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Review the block&lt;/strong&gt;: Follow the block from start to finish, making note of
the line in question. Try to get a good sense of how that code is working.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scan any higher scopes&lt;/strong&gt;: Make sure you understand at a high-level what the
code is doing and what variables are needed/expected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make a hypothesis&lt;/strong&gt;: You are a scientist, after all. Make an educated guess
about what went wrong and what will fix it. Make sure to review your
hypothesis while you&#39;re debugging.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;additional-reading&quot; tabindex=&quot;-1&quot;&gt;Additional reading&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/before-debugging/#additional-reading&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Additional reading”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jvns.ca/blog/debugging-attitude-matters/&quot;&gt;&lt;em&gt;When debugging, your attitude matters&lt;/em&gt;&lt;/a&gt;
by Julia Evans&lt;/li&gt;
&lt;/ul&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Debugging&quot;&gt;https://en.wikipedia.org/wiki/Debugging&lt;/a&gt; &lt;a href=&quot;https://seanmcp.com/articles/before-debugging/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Fri, 10 Jul 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/before-debugging/</guid>
    </item>
    <item>
      <title>Nodemon for Deno</title>
      <link>https://seanmcp.com/articles/nodemon-for-deno/</link>
      <description>&lt;p&gt;&lt;em&gt;Update: As of Deno v1.4, there is a built in watch mode that you can enable
with the &lt;code&gt;--watch&lt;/code&gt; flag.
&lt;a href=&quot;https://deno.land/posts/v1.4#codedeno-run---watchcode&quot;&gt;Read more about that here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nodemon, or as I read it in my head &lt;em&gt;Nodémon!&lt;/em&gt;, is a utility for restarting
Node.js processes when the source changes. It&#39;s is the first dev dependency I
add when working in Node, because it is so handy!&lt;/p&gt;
&lt;p&gt;Deno, the secure runtime for JavaScript and TypeScript, doesn&#39;t work with
Nodemon. When I first started building with Deno, I was reminded just how
annoying it is to stop and start your server whenever there is a change.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://deno.land/x/denon&quot;&gt;Enter &lt;strong&gt;denon&lt;/strong&gt;&lt;/a&gt;, the &amp;quot;replacement&amp;quot; for Nodemon in
Deno land. As long as you&#39;re using &lt;code&gt;deno@^1.0.1&lt;/code&gt;, you can get all the goodness
of automattic restarting with denon.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;install&quot; tabindex=&quot;-1&quot;&gt;Install&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/nodemon-for-deno/#install&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Install”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;You can install denon with Deno&#39;s &lt;code&gt;install&lt;/code&gt; command:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;deno &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --allow-read --allow-run --allow-write --allow-net &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--unstable&lt;/span&gt; https://deno.land/x/denon@v2.2.0/denon.ts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That command installs denon version &lt;code&gt;2.2.0&lt;/code&gt;, so reference
&lt;a href=&quot;https://deno.land/x/denon#install&quot;&gt;the documentation for the most up-to-date instructions&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;simple-usage&quot; tabindex=&quot;-1&quot;&gt;Simple usage&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/nodemon-for-deno/#simple-usage&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Simple usage”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Once you have denon installed, you can use it as a straight replacement for all
&lt;code&gt;deno&lt;/code&gt; commands:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# With Deno&lt;/span&gt;
deno run --allow-net https://deno.land/std/examples/echo_server.ts

&lt;span class=&quot;token comment&quot;&gt;# With denon&lt;/span&gt;
denon run --allow-net https://deno.land/std/examples/echo_server.ts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the same behavior as &lt;code&gt;node/nodemon&lt;/code&gt;. But running external code doesn&#39;t
really illustrate the value of denon.&lt;/p&gt;
&lt;p&gt;To see it in action, copy &lt;code&gt;echo_server.ts&lt;/code&gt; locally and then run with denon:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;denon run --allow-net echo_server.ts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when you make any changes to the source, you will see denon automatically
restart the server.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;configuration&quot; tabindex=&quot;-1&quot;&gt;Configuration&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/nodemon-for-deno/#configuration&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Configuration”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;My favorite feature of denon is its configuration file: &lt;code&gt;denon.json&lt;/code&gt;. With it,
you get some of the &amp;quot;scripts&amp;quot; features of Node.js&#39;s &lt;code&gt;package.json&lt;/code&gt; that are
currently missing in Deno.&lt;/p&gt;
&lt;p&gt;To create a configuration file, you can call denon with the &lt;code&gt;--init&lt;/code&gt; flag:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;denon &lt;span class=&quot;token parameter variable&quot;&gt;--init&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a &lt;code&gt;denon.json&lt;/code&gt; file where you can include scripts with
commands, permissions, and environment variables.&lt;/p&gt;
&lt;p&gt;We can create a &amp;quot;start&amp;quot; script for the &lt;code&gt;echo_server.ts&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;$schema&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://deno.land/x/denon/schema.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;cmd&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;deno run echo_server.ts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;desc&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Start echo_server in watch mode&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;allow&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;net&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;env&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token property&quot;&gt;&quot;PORT&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2525&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our &amp;quot;start&amp;quot; script has a command, description, permissions to allow, and an
environment variable &lt;code&gt;PORT&lt;/code&gt; that we are passing to our server.&lt;/p&gt;
&lt;p&gt;To run the script, type:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;denon start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you&#39;re off to the races! I love the ability to start a Deno process without
typing all those permissions. :chefs-kiss:&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;learn-more&quot; tabindex=&quot;-1&quot;&gt;Learn more&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/nodemon-for-deno/#learn-more&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Learn more”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href=&quot;https://deno.land/x/denon&quot;&gt;denon documentation&lt;/a&gt; lists the full feature set
and includes a bunch of helpful examples. Make sure to check that out when
setting up denon on your next Deno project.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Wed, 01 Jul 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/nodemon-for-deno/</guid>
    </item>
    <item>
      <title>Parse argument aliases in Deno</title>
      <link>https://seanmcp.com/articles/parse-argument-aliases-in-deno/</link>
      <description>&lt;p&gt;You can parse command-line arguments in Deno with the
&lt;a href=&quot;https://deno.land/std/flags&quot;&gt;standard &lt;code&gt;flags&lt;/code&gt; module&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; parse &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://deno.land/std/flags/mod.ts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;deno run https://deno.land/std/examples/flags.ts &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; beep &lt;span class=&quot;token parameter variable&quot;&gt;-b&lt;/span&gt; boop

&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; _: &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;, a: &lt;span class=&quot;token string&quot;&gt;&#39;beep&#39;&lt;/span&gt;, b: &lt;span class=&quot;token string&quot;&gt;&#39;boop&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;parse&lt;/code&gt; function has a second options argument where you can assign aliases.
Before we do that, let&#39;s use a more description example.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;example-scenario&quot; tabindex=&quot;-1&quot;&gt;Example scenario&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/parse-argument-aliases-in-deno/#example-scenario&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Example scenario”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Say you have a script, &lt;code&gt;log.ts&lt;/code&gt;, that takes a message to display in the
terminal. We would use our script like this:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;deno run log.ts &lt;span class=&quot;token parameter variable&quot;&gt;--message&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello world&quot;&lt;/span&gt;

Hello world&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&#39;s alias the &lt;code&gt;--message&lt;/code&gt; flag to &lt;code&gt;-M&lt;/code&gt; for ease of use.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;alias-option&quot; tabindex=&quot;-1&quot;&gt;Alias option&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/parse-argument-aliases-in-deno/#alias-option&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Alias option”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;When we call &lt;code&gt;parse&lt;/code&gt; in our script on &lt;code&gt;Deno.args&lt;/code&gt;, we want to provide an
additional options object with a key &lt;code&gt;aliases&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That will be assigned to another object that will map flags to their aliases:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// log.ts&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; parse &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://deno.land/std/flags/mod.ts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; flagToAliasMap &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;M&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; parsedArgs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;aliases&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; flagToAliasMap &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parsedArgs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can call our script with those aliases:&lt;/p&gt;
&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;deno run log.ts &lt;span class=&quot;token parameter variable&quot;&gt;-M&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;That&#39;s better&quot;&lt;/span&gt;

That&#39;s better&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, the &lt;code&gt;flags&lt;/code&gt; module does all of the hard lifting for you!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap up&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/parse-argument-aliases-in-deno/#wrap-up&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Wrap up”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Two things to note about aliases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;flags&lt;/code&gt; doesn&#39;t care whether you use one or two hyphens for aliases, so &lt;code&gt;-M&lt;/code&gt;
and &lt;code&gt;--M&lt;/code&gt; will both work.&lt;/li&gt;
&lt;li&gt;Aliases &lt;strong&gt;are&lt;/strong&gt; case sensitive, so you&#39;ll have to map &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;M&lt;/code&gt; separately.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Fri, 26 Jun 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/parse-argument-aliases-in-deno/</guid>
    </item>
    <item>
      <title>Await multiple promises in JavaScript</title>
      <link>https://seanmcp.com/articles/await-multiple-promises-in-javascript/</link>
      <description>&lt;p&gt;Let&#39;s say I have two promises: the former resolves in three seconds, while the
latter resolves in five. I need to wait for both of these before moving on to
the next code block.&lt;/p&gt;
&lt;p&gt;Depending on how you structure your promises, you will either have to wait five
seconds or eight seconds before moving on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is the best way to await multiple promises?&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;await-happy&quot; tabindex=&quot;-1&quot;&gt;Await happy&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/await-multiple-promises-in-javascript/#await-happy&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Await happy”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;My first instinct in the above scenario was to use to await both promises.
&lt;code&gt;await&lt;/code&gt; is such a useful keyword in modern JS, that I tend to throw it places
without a second thought:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;promiseOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Resolves in three seconds&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;promiseTwo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Resolves in five seconds&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;done&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks neat and clean, but how long will it take to resolve? &lt;strong&gt;8 seconds&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Look back at the first line. We&#39;re asking the JavaScript engine to await the
resolution of &lt;code&gt;promiseOne&lt;/code&gt;. In effect, we&#39;re asking it to twiddle its thumbs for
three seconds while we wait on the promise.&lt;/p&gt;
&lt;p&gt;When the first resolves, then JavaScript quickly moves on to the next promise.
After waiting for five seconds, it moves on to the log. 3 seconds + 5 seconds =
8 seconds.&lt;/p&gt;
&lt;p&gt;Can we reduce that wait time by refactoring?&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;call-then-await&quot; tabindex=&quot;-1&quot;&gt;Call then await&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/await-multiple-promises-in-javascript/#call-then-await&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Call then await”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Instead of reaching straight for &lt;code&gt;await&lt;/code&gt;, let&#39;s think this through: we want to
&lt;strong&gt;start&lt;/strong&gt; both promises, &lt;strong&gt;then wait&lt;/strong&gt; for their resolution. So let&#39;s change it
up:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; promiseOnePromise &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;promiseOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; promiseTwoPromise &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;promiseOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; promiseOnePromise&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; promiseTwoPromise&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;done&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How long will it take this code to resolve? &lt;strong&gt;5 seconds&lt;/strong&gt; (roughly).&lt;/p&gt;
&lt;p&gt;By calling the functions that return promises initially, we are &amp;quot;starting the
timer&amp;quot; for both. So the three-second and five-second promises are resolving in
tandem.&lt;/p&gt;
&lt;p&gt;When we &lt;code&gt;await&lt;/code&gt; &lt;strong&gt;after calling the promises&lt;/strong&gt;, we&#39;ll only wait as long as the
slowest promise: five seconds in this case.&lt;/p&gt;
&lt;p&gt;This is great, but there is one more solution that might be easier.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;promise.all&quot; tabindex=&quot;-1&quot;&gt;Promise.all&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/await-multiple-promises-in-javascript/#promise.all&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Promise.all”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Promise&lt;/code&gt; object has an &lt;code&gt;all&lt;/code&gt; method that accepts any number of promises and
resolves when all have been fulfilled. We just need to pass it an iterable like
an array:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promiseOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;promiseTwo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;done&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This functions in a similar manner to the previous &amp;quot;call then await&amp;quot; example but
is more succinct. In my tests, it was fractions of a millisecond slower, but
your mileage may vary.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;live-example&quot; tabindex=&quot;-1&quot;&gt;Live example&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/await-multiple-promises-in-javascript/#live-example&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Live example”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;You can view a
&lt;a href=&quot;https://repl.it/@SeanMcP/await-multiple-promises&quot;&gt;live example of this code on Repl&lt;/a&gt;:&lt;/p&gt;
&lt;iframe height=&quot;500px&quot; width=&quot;100%&quot; src=&quot;https://repl.it/@SeanMcP/await-multiple-promises?lite=true&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot; sandbox=&quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&quot;&gt;&lt;/iframe&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/await-multiple-promises-in-javascript/#conclusion&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Conclusion”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;There we go! Two solutions for how to await multiple promises in JavaScript.
Hope that helped!&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Wed, 17 Jun 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/await-multiple-promises-in-javascript/</guid>
    </item>
    <item>
      <title>TypeScript mega-course on Egghead.io</title>
      <link>https://seanmcp.com/articles/typescript-mega-course-on-egghead/</link>
      <description>&lt;p&gt;&lt;em&gt;This playlist has been updated.
&lt;a href=&quot;https://seanmcp.com/articles/typescript-mega-course-on-egghead/updated-typescript-mega-course-on-egghead&quot;&gt;Check out the latest version of my TypeScript &amp;quot;mega-course&amp;quot; on Egghead.io&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I would say that I have &amp;quot;functional&amp;quot; understanding of TypeScript. I can get the
job done (at least most of the time), but as soon as the types get hairy I
struggle.&lt;/p&gt;
&lt;p&gt;As TypeScript contiues grow in popularity, this will become a liability. To fix
this, I have set a professional goal to improve my understanding of TypeScript.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://Niche.com&quot;&gt;Niche.com&lt;/a&gt; provides us with a membership to &lt;a href=&quot;http://Egghead.io&quot;&gt;Egghead.io&lt;/a&gt;, so I&#39;ve cobbled together
multiple courses on TypeScript:&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;mega-course&quot; tabindex=&quot;-1&quot;&gt;Mega-course&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/typescript-mega-course-on-egghead/#mega-course&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Mega-course”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://egghead.io/courses/up-and-running-with-typescript&quot;&gt;&lt;em&gt;Up and Running with TypeScript&lt;/em&gt;&lt;/a&gt;
by John Lindquist (22 min)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://egghead.io/courses/use-types-effectively-in-typescript&quot;&gt;&lt;em&gt;Use Types Effectively in TypeScript&lt;/em&gt;&lt;/a&gt;
by Ari Picker (29 min)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://egghead.io/courses/async-await-using-typescript&quot;&gt;&lt;em&gt;Async/Await using TypeScript&lt;/em&gt;&lt;/a&gt;
by Basarat Ali Syed (17 min)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://egghead.io/courses/practical-advanced-typescript&quot;&gt;&lt;em&gt;Practical Advanced TypeScript&lt;/em&gt;&lt;/a&gt;
by Rares Matei (62 min)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://egghead.io/courses/advanced-static-types-in-typescript&quot;&gt;&lt;em&gt;Advanced Static Types in TypeScript&lt;/em&gt;&lt;/a&gt;
by Marius Schulz (67 min)&lt;/li&gt;
&lt;li&gt;Optional:
&lt;a href=&quot;https://egghead.io/courses/use-typescript-to-develop-react-applications&quot;&gt;&lt;em&gt;Use TypeScript to develop React Applications&lt;/em&gt;&lt;/a&gt;
by Basarat Ali Syed (27 min)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The plan is to complete these courses over the next three weeks. At the end,
I&#39;ll review the mega-course and update the order if necessary.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Mon, 15 Jun 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/typescript-mega-course-on-egghead/</guid>
    </item>
    <item>
      <title>Six video update</title>
      <link>https://seanmcp.com/articles/six-video-update/</link>
      <description>&lt;p&gt;A few weeks ago, I wrote about
&lt;a href=&quot;https://seanmcp.com/articles/six-video-update/publishing-my-first-youtube-video&quot;&gt;publishing my first YouTube video&lt;/a&gt;. In
that article, I included my reasoning and what I hoped to gain from it.&lt;/p&gt;
&lt;p&gt;My goal is to upload twelve videos, that get an average of twelve views, and get
to twelve subscribers.&lt;/p&gt;
&lt;p&gt;Last night, I uploaded my sixth video,
&lt;a href=&quot;https://www.youtube.com/watch?v=yMEpIOyoizU&quot;&gt;&lt;em&gt;Set Breakpoints In The Chrome DevTools&lt;/em&gt;&lt;/a&gt;,
which puts me at the half-way mark.&lt;/p&gt;
&lt;p&gt;&lt;progress style=&quot;width:100%&quot; min=&quot;0&quot; max=&quot;12&quot; value=&quot;6&quot;&gt;6/12 or 50%&lt;/progress&gt;&lt;/p&gt;
&lt;p&gt;I wanted to share some of the lessons that I learned making and publishing
videos 2-6.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;lessons-learned&quot; tabindex=&quot;-1&quot;&gt;Lessons learned&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/six-video-update/#lessons-learned&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Lessons learned”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;recording-gets-easier&quot; tabindex=&quot;-1&quot;&gt;Recording gets easier&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/six-video-update/#recording-gets-easier&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Recording gets easier”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;For me, it doesn&#39;t feel natural to sit and talk to myself in front of the
computer. But with practice, I found myself getting more comfortable.&lt;/p&gt;
&lt;p&gt;There is a long way to go, but it is encouraging to see growth after making six
videos.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;keep-it-rolling&quot; tabindex=&quot;-1&quot;&gt;Keep it rolling&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/six-video-update/#keep-it-rolling&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Keep it rolling”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;By keeping a continous recording, I am able to fix mistakes as they come and
edit them out later. If anything sounds weird as I say it, I just take a break,
and then try the line again.&lt;/p&gt;
&lt;p&gt;This is far easier than trying to get a good &amp;quot;take&amp;quot; of the whole video. I found
that a 3-4 minute video would come from 10-12 minutes of continous recording.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;editing-gets-easier&quot; tabindex=&quot;-1&quot;&gt;Editing gets easier&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/six-video-update/#editing-gets-easier&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Editing gets easier”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I don&#39;t think I could say that I &lt;em&gt;like&lt;/em&gt; iMovie, but I&#39;m getting used to the
interface and the steps that I need to go through to edit my videos.&lt;/p&gt;
&lt;p&gt;The biggest frustration that remains is the slider for audio volume (no input?)
and the tendency to export the source video instead of the editted version (why
is that possible?).&lt;/p&gt;
&lt;p&gt;That being said, I think iMovie will be sufficient for the time being.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;equipment-matters&quot; tabindex=&quot;-1&quot;&gt;Equipment matters&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/six-video-update/#equipment-matters&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Equipment matters”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I started off using a $50 microphone from Amazon. It worked, but the audio
quality wasn&#39;t great and it didn&#39;t provide any control over the recording.&lt;/p&gt;
&lt;p&gt;I traded that in for a Blue Yeti Nano, and the improvement has been noticeable.
I&#39;m still getting into the swing of things, but having the right tools makes a
difference.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;very-few-views&quot; tabindex=&quot;-1&quot;&gt;Very few views&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/six-video-update/#very-few-views&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Very few views”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Since that initial video, I have averaged 1.2 views per video and gained 2
subscribers (one of whom is my wife). This is lower than I expected, but good to
know.&lt;/p&gt;
&lt;p&gt;I want to stress again that &lt;strong&gt;gaining views and subscribers is not by end
game&lt;/strong&gt;. Including those two measurements in the goal was an attempt to gauge the
utility.&lt;/p&gt;
&lt;p&gt;This may be aided by more promotion on my end, but with everything going on in
the world that didn&#39;t seem the most helpful thing to do.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Once I publish my twelfth video, I want to take a deeper dive into the
performance of each video to see what I can glean going forward.&lt;/p&gt;
&lt;p&gt;Until then, &lt;a href=&quot;https://bit.ly/seanmcp-youtube&quot;&gt;happy watching&lt;/a&gt;!&lt;/p&gt;
</description>
      <pubDate>Fri, 12 Jun 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/six-video-update/</guid>
    </item>
    <item>
      <title>Read a json file in Deno</title>
      <link>https://seanmcp.com/articles/read-a-json-file-in-deno/</link>
      <description>&lt;p&gt;Deno is a &lt;strong&gt;secure&lt;/strong&gt; runtine for JavaScript, so to read a file the program needs
explicit permissions. We can enable file reading with the &lt;code&gt;--allow-read&lt;/code&gt; flag in
the command line:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;deno run --allow-read read-json.ts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the permissions are straight, we need to read the file. There are a few
methods on the &lt;code&gt;Deno&lt;/code&gt; module to use, so let&#39;s look at two options: &lt;code&gt;readFile&lt;/code&gt;,
and &lt;code&gt;readTextFile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&#39;s take a look at them separately.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;readfile&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;readFile&lt;/code&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/read-a-json-file-in-deno/#readfile&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “readFile”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Deno&#39;s &lt;code&gt;readFile&lt;/code&gt; method returns a Promise resolves with a Uint8Array. You can
call the method like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So if we run the following code in a directory with a &lt;code&gt;data.json&lt;/code&gt; file, you
would see a log like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Uint8Array(29) [
  123,  10,  32,  32,  32, 32,  34, 115,
  111, 117, 114,  99, 101, 34,  58,  32,
   34, 100,  97, 116,  97, 46, 106, 115,
  111, 110,  34,  10, 125
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to read this, we need a new text decoder decoder with and pass the
file&#39;s encoding:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; decoder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextDecoder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;decoder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when we run the code, we see the contents of &lt;code&gt;data.json&lt;/code&gt; logged in the
console:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &amp;quot;source&amp;quot;: &amp;quot;data.json&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks good, but it is just a formatted string. To consume this data, we
need to use the global &lt;code&gt;JSON&lt;/code&gt; object&#39;s &lt;code&gt;parse&lt;/code&gt; method to get a usuable json
object.&lt;/p&gt;
&lt;!-- ```js/2 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; decoder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextDecoder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;decoder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run it again, and you will see whatever data you had stored in your json file
logged to the console. You have successfully read a json file in Deno with
&lt;code&gt;readFile&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;If you know that your data is utf8 encoded, you can skip a step with the next
Deno method.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;readtextfile&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;readTextFile&lt;/code&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/read-a-json-file-in-deno/#readtextfile&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “readTextFile”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Deno&#39;s &lt;code&gt;readTextFile&lt;/code&gt; method returns a Promise that resolves to a utf8 decoded
string. You can call the method like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readTextFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once again, if we run this code in a directory with a &lt;code&gt;data.json&lt;/code&gt; file, you
would see the file&#39;s contents logged in the console:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &amp;quot;source&amp;quot;: &amp;quot;data.json&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks good, but just like before it is only a formatted string. To consume
this data, we need to use the global &lt;code&gt;JSON&lt;/code&gt; object&#39;s &lt;code&gt;parse&lt;/code&gt; method again to get
a usuable json object.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Deno&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readTextFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run it again, and you will see whatever data you had stored in your json file
logged to the console. You have successfully read a json file in Deno with
&lt;code&gt;readTextFile&lt;/code&gt;!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/read-a-json-file-in-deno/#conclusion&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Conclusion”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;If you know that your file is utf8 encoded, using &lt;code&gt;Deno.readTextFile&lt;/code&gt; is an easy
way to grab the contents of a file. Otherwise, &lt;code&gt;Deno.readFile&lt;/code&gt; and a decoder can
get you on your way.&lt;/p&gt;
&lt;p&gt;Whichever method you choose, just remember to parse the json data before trying
to consume it.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Thu, 28 May 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/read-a-json-file-in-deno/</guid>
    </item>
    <item>
      <title>Read a json file in Node.js</title>
      <link>https://seanmcp.com/articles/read-a-json-file-in-node-js/</link>
      <description>&lt;p&gt;To read any file in Node.js, you need to import the &lt;code&gt;fs&lt;/code&gt; or file system module.
From there, you have two methods from which to choose: &lt;code&gt;readFile&lt;/code&gt;, and
&lt;code&gt;readFileSync&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Both are similar in that they return
&lt;a href=&quot;https://nodejs.org/dist/latest-v14.x/docs/api/buffer.html#buffer_buffer&quot;&gt;a Buffer of binary data&lt;/a&gt;
from a file. &lt;code&gt;readFile&lt;/code&gt; accepts a callback that will receive the Buffer, while
&lt;code&gt;readFileSync&lt;/code&gt; returns it synchronously.&lt;/p&gt;
&lt;p&gt;In action, they look like:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./data.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  error &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./data.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you run this code in a directory with a &lt;code&gt;data.json&lt;/code&gt; file, boths methods will
log something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Buffer 7b 0a 20 20 22 64 61 74 61 22 3a 20 74 72 75 65 0a 7d&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both are returning the same data, but it isn&#39;t consumable. In most instances,
you will need to do one more operation in order to use the data that you have
read from a file.&lt;/p&gt;
&lt;p&gt;Since we are working with a json file, we can use the global &lt;code&gt;JSON&lt;/code&gt; object to
read the data. The &lt;code&gt;parse&lt;/code&gt; method will convert this Buffer into a usuable JSON
object:&lt;/p&gt;
&lt;!-- ```js/3,7 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./data.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
  error &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFileSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;./data.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run it again, and you will see whatever data you had stored in your json file
logged to the console. You have successfully read a json file in Node.js!&lt;/p&gt;
&lt;p&gt;You can see the code in action here:&lt;/p&gt;
&lt;iframe height=&quot;500px&quot; width=&quot;100%&quot; src=&quot;https://repl.it/@SeanMcP/Read-json-file-in-Nodejs?lite=true&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot; sandbox=&quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Wed, 27 May 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/read-a-json-file-in-node-js/</guid>
    </item>
    <item>
      <title>Publishing my first YouTube video</title>
      <link>https://seanmcp.com/articles/publishing-my-first-youtube-video/</link>
      <description>&lt;p&gt;Yesterday, I published my first video on YouTube:
&lt;a href=&quot;https://www.youtube.com/watch?v=1bjwBppbpxk&quot;&gt;&amp;quot;Three Ways To Open The Firefox DevTools&amp;quot;&lt;/a&gt;.
As the title suggests, it covers the three main ways of opening the DevTools in
Firefox, the browser menu, &amp;quot;Inspect Element&amp;quot;, and the keyboard shortcut.&lt;/p&gt;
&lt;p&gt;This is new territory for me, so I wanted to take a moment and reflect on why I
started a YouTube channel, what I hope to gain from it, and what I learned in
the process.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;a-new-career-goal&quot; tabindex=&quot;-1&quot;&gt;A new career goal&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/publishing-my-first-youtube-video/#a-new-career-goal&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “A new career goal”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Before working as a software engineer, I worked for three years as a teacher.
And while that specific career was right for me, I am still passionate about
education and sharing what I know with others. So I am making it a career goal
to teach on the side.&lt;/p&gt;
&lt;p&gt;This focus will complement my work as an engineer for all the wonderful ways
that teaching is helpful. It will help me be a better team member and mentor at
work. And it is an opportunity to give back to a developer community that has
already given me so much.&lt;/p&gt;
&lt;p&gt;Eventually, I would like to lead workshops and teach on-line courses, but that
is more of a 3-5 year plan.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;plans-for-youtube&quot; tabindex=&quot;-1&quot;&gt;Plans for YouTube&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/publishing-my-first-youtube-video/#plans-for-youtube&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Plans for YouTube”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I am going to produce short, informative videos in the same style as &lt;a href=&quot;http://Egghead.io&quot;&gt;Egghead.io&lt;/a&gt;.
I have really enjoyed their content and think that there is a strong formula for
laser-focused content.&lt;/p&gt;
&lt;p&gt;With that in mind, I&#39;m aiming for videos in the 3-10 minute range: long enough
to be valuable, but not long winded.&lt;/p&gt;
&lt;p&gt;My goal for YouTube is to put out twelve videos that have an average of twelve
views and gain twelve subscribers. I&#39;m hoping that this will take three months,
but I don&#39;t want to commit to a hard timeline.&lt;/p&gt;
&lt;p&gt;After hitting twelve videos, I will reassess my efforts and determine if YouTube
is the right platform for this.&lt;/p&gt;
&lt;p&gt;So this first video puts me one step on that journey.&lt;/p&gt;
&lt;p&gt;&lt;progress max=&quot;12&quot; value=&quot;1&quot; style=&quot;width:100%&quot;&gt;1/12&lt;/progress&gt;&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;lessons-learned&quot; tabindex=&quot;-1&quot;&gt;Lessons learned&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/publishing-my-first-youtube-video/#lessons-learned&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Lessons learned”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;harder-than-it-looks&quot; tabindex=&quot;-1&quot;&gt;Harder than it looks&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/publishing-my-first-youtube-video/#harder-than-it-looks&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Harder than it looks”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In a world of endless high-quality content on YouTube, it&#39;s easy to assume that
making videos is easy. At least that&#39;s what I did. But every step of the process
was more difficult that I had anticipated.&lt;/p&gt;
&lt;p&gt;Writing, recording, and editing are all skills unto themselves, and ones that I
am not very good at. All of this will require practice.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;i-need-a-script&quot; tabindex=&quot;-1&quot;&gt;I need a script&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/publishing-my-first-youtube-video/#i-need-a-script&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “I need a script”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;When I was teaching, some lesson plans had a script for the teacher to read. In
front of the classroom, I found this restricting and would avoid reading
verbatim.&lt;/p&gt;
&lt;p&gt;In front of a screen, however, the dynamic changes. You can&#39;t see faces to meter
your delivery and the lesson pace. As a result, I find myself getting further
off-topic during digital instruction than I did in-person.&lt;/p&gt;
&lt;p&gt;But with a script, it&#39;s different. I can plan my thoughts ahead of time and hit
all the intended points, only lingering when I intend. Writing this kind of
script is a skill that I&#39;m developing, but they are a valuable part of the
lesson.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;things-to-improve&quot; tabindex=&quot;-1&quot;&gt;Things to improve&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/publishing-my-first-youtube-video/#things-to-improve&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Things to improve”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;editing&quot; tabindex=&quot;-1&quot;&gt;Editing&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/publishing-my-first-youtube-video/#editing&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Editing”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I edited this video with iMovie, and it was a new experience. The &amp;quot;Project&amp;quot;
structure is a little confusing, and I had a little bit of trouble importing the
video. But the biggest hangup was the preview, which would occassionally not
follow the scrubber.&lt;/p&gt;
&lt;p&gt;As a result, I didn&#39;t edit this video as much as I would have liked. Going
forward, I want to watch a few videos on editing in iMovie and see if I can
resolve those issues.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;multiple-takes&quot; tabindex=&quot;-1&quot;&gt;Multiple takes&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/publishing-my-first-youtube-video/#multiple-takes&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Multiple takes”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Going into filming, I planned to get everything correct in one go. When
something went wrong, I stopped the recording, reset, and then started from
scratch.&lt;/p&gt;
&lt;p&gt;That is not sustainable. Instead, I want to keep the &amp;quot;film rolling.&amp;quot; If I mess
up, just wait a beat and do the line correctly. This should increase the
recordig process because I&#39;m not repeating lines that are good for the sake of
ones that need fixed.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;mouth-sounds&quot; tabindex=&quot;-1&quot;&gt;Mouth sounds&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/publishing-my-first-youtube-video/#mouth-sounds&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Mouth sounds”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Hoo boy, do I make a lot of mouth sounds. My wife had some helpful suggestions
that I am going to try in the next recording:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Stay hydrated: Keep a glass of water on hand and drink when you&#39;re thirsty&lt;/li&gt;
&lt;li&gt;Record one line at a time: Whether that is a sentence or a paragraph, do it
in one go without swallowing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once I can isolate the content better, it will be easier for me to edit out
those unpleasant sounds.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I plan to post an update on my goal once I&#39;ve hit the &amp;quot;six video&amp;quot; mark. Until
then you can
&lt;a href=&quot;https://www.youtube.com/channel/UC5KVcnzcZn_zCYXGR1ErV_A&quot;&gt;watch my progress on YouTube&lt;/a&gt;
and &lt;a href=&quot;https://bit.ly/subscribe-seanmcp&quot;&gt;subscribe to stay updated&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy watching!&lt;/p&gt;
</description>
      <pubDate>Wed, 20 May 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/publishing-my-first-youtube-video/</guid>
    </item>
    <item>
      <title>How to get the browser and version in JavaScript</title>
      <link>https://seanmcp.com/articles/how-to-get-the-browser-version-in-javascript/</link>
      <description>&lt;p&gt;For a recent project, I wanted to display the browser and version on the screen.
I figured that this would be possible in JavaScript, so I went searching around.&lt;/p&gt;
&lt;p&gt;This led me to the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent&quot;&gt;User-Agent&lt;/a&gt;,
&lt;a href=&quot;https://en.wikipedia.org/wiki/User_agent#User_agent_sniffing&quot;&gt;&amp;quot;sniffing&amp;quot;&lt;/a&gt;, and
its
&lt;a href=&quot;https://www.w3.org/community/webed/wiki/Optimizing_content_for_different_browsers:_the_RIGHT_way#A_brief_history_of_browser_sniffing&quot;&gt;wild and crazy history&lt;/a&gt;.
I also read a bunch of articles on why serving different content to different
browsers is a bad idea.
&lt;a href=&quot;https://seanmcp.com/articles/how-to-get-the-browser-version-in-javascript/#additional-reading&quot;&gt;I&#39;ll link them at the bottom of this article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I just want to display the browser and version, so the referencing the user
agent is a fine enough solution
(&lt;a href=&quot;https://css-tricks.com/freezing-user-agent-strings/&quot;&gt;even if temporary&lt;/a&gt;).
&lt;strong&gt;But you should definitely think twice before you go user agent sniffing&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;accessing-the-user-agent&quot; tabindex=&quot;-1&quot;&gt;Accessing the user agent&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-get-the-browser-version-in-javascript/#accessing-the-user-agent&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Accessing the user agent”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;You can access the user agent from the read-only
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Navigator&quot;&gt;global &lt;code&gt;Navigator&lt;/code&gt; interface&lt;/a&gt;.
That&#39;s as simple as writing:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depending on your browser, you should see a few different outputs:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Firefox&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Chrome&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Edge (Chromium)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 Edg/81.0.416.77&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Safari&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are fascinating, but for this article we are only interested in the
differences. If we just look at the tail for each, we get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Firefox: &lt;code&gt;&amp;quot;Firefox/77.0&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Chrome: &lt;code&gt;&amp;quot;Chrome/81.0.4044.138 Safari/537.36&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Edge (Chromium): &lt;code&gt;&amp;quot;Chrome/81.0.4044.138 Safari/537.36 Edg/81.0.416.77&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Safari: &lt;code&gt;&amp;quot;Version/13.1 Safari/605.1.15&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this, we know have enough information to parse the string.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;sniffing-logic&quot; tabindex=&quot;-1&quot;&gt;Sniffing logic&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-get-the-browser-version-in-javascript/#sniffing-logic&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Sniffing logic”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Chrome, Edge, and Safari all identify as &amp;quot;Safari&amp;quot;, so let&#39;s start our logic with
the simplest user agent: Firefox. After that, it&#39;s a process of determining who
has a unique string to search for:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; userAgent &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Firefox/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Firefox&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Edg/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Edge (Chromium)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Chrome/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Chrome&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Safari/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Safari&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you can identify the browser from the user agent, it&#39;s just a matter of
using your favorite string parsing method to grab the version. Here&#39;s the code
for Firefox:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Firefox/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Firefox&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Firefox v&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;userAgent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Firefox/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you know of a better way, please
&lt;a href=&quot;https://twitter.com/intent/tweet?text=.@snmcp&quot;&gt;tweet me your solution&lt;/a&gt; and I&#39;ll
give you a shoutout here.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;additional-reading&quot; tabindex=&quot;-1&quot;&gt;Additional reading&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-get-the-browser-version-in-javascript/#additional-reading&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Additional reading”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent&quot;&gt;&lt;em&gt;Browser detection using the user agent&lt;/em&gt;&lt;/a&gt;
on MDN&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/browser-detection-is-bad/&quot;&gt;&lt;em&gt;Browser Detection is Bad&lt;/em&gt;&lt;/a&gt;
by Chris Coyier on CSS-Tricks&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webaim.org/blog/user-agent-string-history/&quot;&gt;&lt;em&gt;History of the browser user-agent string&lt;/em&gt;&lt;/a&gt;
by Aaron Andersen on WebAIM&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/community/webed/wiki/Optimizing_content_for_different_browsers:_the_RIGHT_way&quot;&gt;&lt;em&gt;Optimizing content for different browsers: the RIGHT way § 2.2&lt;/em&gt;&lt;/a&gt;
on W3&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Tue, 19 May 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/how-to-get-the-browser-version-in-javascript/</guid>
    </item>
    <item>
      <title>Logging with Eleventy and Nunjucks</title>
      <link>https://seanmcp.com/articles/logging-with-eleventy-and-nunjucks/</link>
      <description>&lt;p&gt;This site was forked from the
&lt;a href=&quot;https://github.com/11ty/eleventy-base-blog&quot;&gt;Eleventy base blog&lt;/a&gt; and uses
&lt;a href=&quot;https://mozilla.github.io/nunjucks/&quot;&gt;Nunjucks templates&lt;/a&gt;. When everything is
working, it is as smooth as can be. But when I run into an issue, I often find
it difficult to debug.&lt;/p&gt;
&lt;p&gt;Recently I was trying to do some logical rendering based on article tags. I knew
the information was at my finger tips, but I couldn&#39;t guess the right key. &lt;strong&gt;All
I need is a simple &lt;code&gt;console.log()&lt;/code&gt;&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;I searched combinations like &amp;quot;debugging in eleventy&amp;quot; and &amp;quot;console logging in
nunjucks&amp;quot;, but none of the suggestions quite worked. But they did give me an
idea: a custom filter for logging.&lt;/p&gt;
&lt;p&gt;Opening up &lt;code&gt;.eleventy.js&lt;/code&gt;, I added the following lines:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;eleventyConfig&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;log&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, I could then use the &lt;code&gt;log&lt;/code&gt; filter in my Nunjuck template:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;li class=&amp;quot;article&amp;quot;&amp;gt; ... &amp;lt;/li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I had Eleventy logging the entire article object in the terminal! Exactly
what I needed.&lt;/p&gt;
&lt;p&gt;I tinkered around with returning a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; from the filter to log on the
client too, but that required &lt;code&gt;JSON.stringify()&lt;/code&gt; and piping the result into the
&lt;code&gt;safe&lt;/code&gt; filter. That was more than I wanted to mess with, but there might be a
solution there that works for you.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Tue, 12 May 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/logging-with-eleventy-and-nunjucks/</guid>
    </item>
    <item>
      <title>Store readable data</title>
      <link>https://seanmcp.com/articles/store-readable-data/</link>
      <description>&lt;p&gt;Imagine that you want to store data to look up the continent for every country
in the world. The best data structure for this is a object/map/dictionary to
quickly access the value without looping. I&#39;ll use the former for my examples:&lt;/p&gt;
&lt;p&gt;Your object map will look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &amp;quot;Algeria&amp;quot;: &amp;quot;Africa&amp;quot;,
    &amp;quot;Angola&amp;quot;: &amp;quot;Africa&amp;quot;,
    &amp;quot;Benin&amp;quot;: &amp;quot;Africa,
    // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is well and good, but you&#39;ll notice one bit of data is repeated: continent.
Any time you have the same bit of data repeated, you run the risk of typing it
incorrectly: &lt;code&gt;&amp;quot;Africa&amp;quot; != &amp;quot;Afrcia&amp;quot;&lt;/code&gt;. This is smell number one.&lt;/p&gt;
&lt;p&gt;But let&#39;s ignore that for now. We want to include all of the countries in the
world, so let&#39;s add a few more:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &amp;quot;Afghanistan&amp;quot;: &amp;quot;Asia&amp;quot;,
    &amp;quot;Algeria&amp;quot;: &amp;quot;Africa&amp;quot;,
    &amp;quot;Argentina&amp;quot;: &amp;quot;South America&amp;quot;,
    &amp;quot;Armenia&amp;quot;: &amp;quot;Asia&amp;quot;,
    &amp;quot;Azerbaijan&amp;quot;: &amp;quot;Asia&amp;quot;,
    &amp;quot;Angola&amp;quot;: &amp;quot;Africa&amp;quot;,
    &amp;quot;Benin&amp;quot;: &amp;quot;Africa,
    &amp;quot;Bolivia&amp;quot;: &amp;quot;South America&amp;quot;,
    &amp;quot;Brazil&amp;quot;: &amp;quot;South America&amp;quot;,
    // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As this structure grows to accommodate all of our data, it becomes less for
humans and therefore less maintainable.&lt;/p&gt;
&lt;p&gt;South America has 3 countries and/or territories that start with &amp;quot;B&amp;quot;... do we
have them all? It&#39;s possible to answer that question, but it&#39;s not easy. This is
is smell number two.&lt;/p&gt;
&lt;p&gt;Instead of continuing down this path, let&#39;s go back to the drawing board.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;best-for-whom%3F&quot; tabindex=&quot;-1&quot;&gt;Best for whom?&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/store-readable-data/#best-for-whom%3F&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Best for whom?”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Our decision in choosing a data structure was to do what is best &lt;em&gt;for the
computer&lt;/em&gt;. Objects are a quick and easy way to retrieve the information that we
need.&lt;/p&gt;
&lt;p&gt;But in making that decision, we assumed that the best option was what is best
for the computer. Instead, what if we stored data in the way that is best &lt;em&gt;for
the human&lt;/em&gt; maintaining it?&lt;/p&gt;
&lt;p&gt;We would still start with an object/map/dictionary, but countries wouldn&#39;t be at
the top level:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &amp;quot;Africa&amp;quot;: [
        &amp;quot;Algeria&amp;quot;,
        &amp;quot;Angola&amp;quot;,
        &amp;quot;Benin&amp;quot;,
        // ...
    ],
    // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead we would put continents first. Why? Because our brains like to organize
the information we encounter into useful groups. In this scenario, the most
useful arrangement for counties is by continent.&lt;/p&gt;
&lt;p&gt;With this approach, we made it easier to read and maintain, and removed
duplicated data.&lt;/p&gt;
&lt;p&gt;However, this structure is harder for the computer to read. So before we start
this loop over again, let&#39;s add one more bit of code: a transformer.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;transformer&quot; tabindex=&quot;-1&quot;&gt;Transformer&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/store-readable-data/#transformer&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Transformer”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;This is a function that will take our data in a particular format and
&amp;quot;transform&amp;quot; it into another. In our example, it will turn our human readable
code and turn it into computer usable code.&lt;/p&gt;
&lt;p&gt;The implementation of this particular function isn&#39;t important, so just focus on
the input and output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;humanReadable = {
    &amp;quot;Africa&amp;quot;: [
        &amp;quot;Algeria&amp;quot;,
        &amp;quot;Angola&amp;quot;,
        &amp;quot;Benin&amp;quot;,
    ]
}

computerUsable = {
    &amp;quot;Algeria&amp;quot;: &amp;quot;Africa&amp;quot;,
    &amp;quot;Angola&amp;quot;: &amp;quot;Africa&amp;quot;,
    &amp;quot;Benin&amp;quot;: &amp;quot;Africa&amp;quot;,
}

transformer(humanReadable) = computerUsable
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we run the transformer once at the beginning of our code, we now have the
readibility of the first structure &lt;em&gt;and&lt;/em&gt; the usability of the second.&lt;/p&gt;
&lt;p&gt;So store readable data. You, or the developer after you, will thank you for it.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Mon, 11 May 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/store-readable-data/</guid>
    </item>
    <item>
      <title>How to open the Dev Tools</title>
      <link>https://seanmcp.com/articles/how-to-open-dev-tools/</link>
      <description>&lt;p&gt;As a web developer, one of the most powerful tools in your arsenal is the
browser&#39;s developer tools.&lt;/p&gt;
&lt;p&gt;Here is a list of all the ways to access the dev tools for your browser and
operating system.&lt;/p&gt;
&lt;hr&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;with-your-mouse&quot; tabindex=&quot;-1&quot;&gt;With your mouse&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#with-your-mouse&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “With your mouse”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;in-the-window&quot; tabindex=&quot;-1&quot;&gt;In the window&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#in-the-window&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “In the window”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;You can enter the dev tools with the mouse by right clicking on any element. In
the menu that appears, select &amp;quot;Inspect&amp;quot; or &amp;quot;Inspect Element&amp;quot;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chrome&lt;/strong&gt;: &lt;code&gt;Right click &amp;gt; Inspect&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Firefox&lt;/strong&gt;: &lt;code&gt;Right click &amp;gt; Inspect Element&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;through-settings&quot; tabindex=&quot;-1&quot;&gt;Through settings&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#through-settings&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Through settings”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;You can also enter the dev tools through your browser&#39;s settings menu.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chrome&lt;/strong&gt;: &lt;code&gt;Three dot menu &amp;gt; More tools &amp;gt; Developer tools&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Firefox&lt;/strong&gt;: &lt;code&gt;Three bar menu &amp;gt; Web Developer &amp;gt; Toggle Tools&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;keyboard-shortcuts&quot; tabindex=&quot;-1&quot;&gt;Keyboard shortcuts&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#keyboard-shortcuts&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Keyboard shortcuts”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Beyond the mouse, there are shortcuts that you can use to open the dev tools
without leaving your keyboard.&lt;/p&gt;
&lt;p&gt;The shortcuts differ by browser and operating system, so I&#39;ve tried to group
them logically below.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; Windows and Linux commands are the same, so I&#39;ve
comibined them into &amp;quot;Win/Lin&amp;quot;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;elements%2Finspector&quot; tabindex=&quot;-1&quot;&gt;Elements/Inspector&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#elements%2Finspector&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Elements/Inspector”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The default tab, it allows you to inspect and edit the elements in the DOM,
their properties, and styles.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h4 id=&quot;chrome-%26-firefox&quot; tabindex=&quot;-1&quot;&gt;Chrome &amp;amp; Firefox&lt;/h4&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#chrome-%26-firefox&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Chrome &amp;amp; Firefox”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: &lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;option&lt;/kbd&gt; + &lt;kbd&gt;c&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Win/Lin&lt;/strong&gt;: &lt;kbd&gt;control&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;c&lt;/kbd&gt; &lt;strong&gt;OR&lt;/strong&gt;
&lt;kbd&gt;F12&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;console&quot; tabindex=&quot;-1&quot;&gt;Console&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#console&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Console”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;This tab prints the console calls from your code and allows you to write
JavaScript that interacts with the current web page.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h4 id=&quot;chrome&quot; tabindex=&quot;-1&quot;&gt;Chrome&lt;/h4&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#chrome&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Chrome”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: &lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;option&lt;/kbd&gt; + &lt;kbd&gt;j&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Win/Lin&lt;/strong&gt;: &lt;kbd&gt;control&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;j&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h4 id=&quot;firefox&quot; tabindex=&quot;-1&quot;&gt;Firefox&lt;/h4&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#firefox&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Firefox”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: &lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;option&lt;/kbd&gt; + &lt;kbd&gt;k&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Win/Lin&lt;/strong&gt;: &lt;kbd&gt;control&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;k&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;debugger&quot; tabindex=&quot;-1&quot;&gt;Debugger&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#debugger&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Debugger”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;This tab shows all the source code for your project and allows you to debug with
breakpoints.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h4 id=&quot;firefox-1&quot; tabindex=&quot;-1&quot;&gt;Firefox&lt;/h4&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#firefox-1&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Firefox”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: &lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;option&lt;/kbd&gt; + &lt;kbd&gt;z&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Win/Lin&lt;/strong&gt;: &lt;kbd&gt;control&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;z&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;network&quot; tabindex=&quot;-1&quot;&gt;Network&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#network&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Network”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;This tab logs all network requests and provides detailed information about the
responses.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h4 id=&quot;firefox-2&quot; tabindex=&quot;-1&quot;&gt;Firefox&lt;/h4&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#firefox-2&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Firefox”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: &lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;option&lt;/kbd&gt; + &lt;kbd&gt;e&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Win/Lin&lt;/strong&gt;: &lt;kbd&gt;control&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;e&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;most-recent&quot; tabindex=&quot;-1&quot;&gt;Most recent&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#most-recent&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Most recent”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;This will open the most recently opened tab. In my experience, it&#39;s the shortcut
that I reach for most often.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h4 id=&quot;chrome-%26-firefox-1&quot; tabindex=&quot;-1&quot;&gt;Chrome &amp;amp; Firefox&lt;/h4&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#chrome-%26-firefox-1&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Chrome &amp;amp; Firefox”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: &lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;option&lt;/kbd&gt; + &lt;kbd&gt;i&lt;/kbd&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Win/Lin&lt;/strong&gt;: &lt;kbd&gt;control&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;i&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Phew! That was a bigger undertaking than I first imagined. If I made any
mistakes, &lt;a href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#comment-link&quot;&gt;please let me know&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I hope that helps! Happy tooling!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I spent a good deal of time debating how to outline this article. I
eventually decided to group things by dev tool tab instead of browser or
operating system. There is more in common than not, so this seemed the
simplest. &lt;a href=&quot;https://seanmcp.com/articles/how-to-open-dev-tools/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Wed, 15 Apr 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/how-to-open-dev-tools/</guid>
    </item>
    <item>
      <title>Tools for custom Slack emojis</title>
      <link>https://seanmcp.com/articles/tools-for-custom-slack-emojis/</link>
      <description>&lt;p&gt;Custom emojis are a fun way to customize your Slack workplace. The fun, silly,
and can provide some genuine utility for the rest of your team.&lt;/p&gt;
&lt;p&gt;Slack already
&lt;a href=&quot;https://slack.com/help/articles/206870177-Add-custom-emoji&quot;&gt;has a guide for adding custom emojis&lt;/a&gt;,
so I won&#39;t be reinventing the wheel here. But I wanted to share some of the
online tools that I use to whip out some fresh emojis for every occasion.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;tools&quot; tabindex=&quot;-1&quot;&gt;Tools&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/tools-for-custom-slack-emojis/#tools&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Tools”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;google-images&quot; tabindex=&quot;-1&quot;&gt;Google Images&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/tools-for-custom-slack-emojis/#google-images&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Google Images”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;When looking for an emoji, I usually start with
&lt;a href=&quot;https://images.google.com/&quot;&gt;a Google Images search&lt;/a&gt;. Once I get the results, I
use their tools to change the color and the usage rights.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Tools &amp;gt; Color &amp;gt; Transparent&lt;/code&gt;: Gets you those sweet transparent backgrounds&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Tools &amp;gt; Usage Rights&lt;/code&gt;: I don&#39;t often do this because most images are not
correctly labelled, but it&#39;s still good to know&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once I find the perfect image, just right-click and download the image or save
the URL to use in another tool.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;svg-to-png&quot; tabindex=&quot;-1&quot;&gt;SVG to PNG&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/tools-for-custom-slack-emojis/#svg-to-png&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “SVG to PNG”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Sometimes the perfect image from Google is an SVG, but sadly Slack does not
support SVG emojis. &lt;a href=&quot;https://svgtopng.com&quot;&gt;Enter SVG to PNG&lt;/a&gt;, which – you
guessed it – converts SVGs to usable PNGs.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;remove-bg&quot; tabindex=&quot;-1&quot;&gt;Remove BG&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/tools-for-custom-slack-emojis/#remove-bg&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Remove BG”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Other times the perfect image is a JPG or something with a solid white
background. You can use these as emojis, but they don&#39;t look as nice. Instead,
you can take that image
&lt;a href=&quot;https://www.remove.bg&quot;&gt;and easily remove the background with removebg&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;ez-gif&quot; tabindex=&quot;-1&quot;&gt;EZ Gif&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/tools-for-custom-slack-emojis/#ez-gif&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “EZ Gif”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;This is probably my favorite tool on this list because it works so well. Despite
the name, &lt;a href=&quot;https://ezgif.com/&quot;&gt;EZGif.com is for editing all types of images&lt;/a&gt;
with crops, resizes, optimizations, and other effects. The neatest bit is that
you can pipe the output from one edit into another.&lt;/p&gt;
&lt;p&gt;You might start with one image from Google, then crop it, resize it, and
optimize it to make it ready for Slack.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I hope that helps! Happy reacting!&lt;/p&gt;
</description>
      <pubDate>Tue, 14 Apr 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/tools-for-custom-slack-emojis/</guid>
    </item>
    <item>
      <title>Programming reads</title>
      <link>https://seanmcp.com/articles/programming-reads/</link>
      <description>&lt;p&gt;This is an alphabetical list that has helped shape the way that I think about
software engineering.&lt;/p&gt;
&lt;p&gt;At some point in the future I may add some commentary on why I found these
insightful. Until then, you&#39;ll have to form those opinions for yourself.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;articles&quot; tabindex=&quot;-1&quot;&gt;Articles&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/programming-reads/#articles&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Articles”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://signalvnoise.com/posts/3124-give-it-five-minutes&quot;&gt;&lt;em&gt;Give it five minutes&lt;/em&gt;&lt;/a&gt;
by Jason Fried&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://overreacted.io/optimized-for-change/&quot;&gt;&lt;em&gt;Optimize for change&lt;/em&gt;&lt;/a&gt; by Dan
Abramov&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction&quot;&gt;&lt;em&gt;The wrong abstraction&lt;/em&gt;&lt;/a&gt;
by Sandi Metz&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.brandonsmith.ninja/blog/write-code-not-too-much-mostly-functions&quot;&gt;&lt;em&gt;Write code. Not too much. Mostly functions.&lt;/em&gt;&lt;/a&gt;
by Brandon Smith&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://programmingisterrible.com/post/139222674273/write-code-that-is-easy-to-delete-not-easy-to&quot;&gt;&lt;em&gt;Write code that is easy to delete, not easy to extend.&lt;/em&gt;&lt;/a&gt;
by tef&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Fri, 20 Mar 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/programming-reads/</guid>
    </item>
    <item>
      <title>Free to grow</title>
      <link>https://seanmcp.com/articles/free-to-grow-with-tests/</link>
      <description>&lt;!-- Outline

- Holds up to refactoring
- Promotes iteration
- Confidence to grow
--&gt;
&lt;p&gt;&lt;img src=&quot;https://seanmcp.com/img/redwood.min.jpg&quot; alt=&quot;a photograph of an upward shot of redwood trees&quot;&gt;&lt;/p&gt;
&lt;p&gt;I previously
&lt;a href=&quot;https://seanmcp.com/articles/snapshot_test_ui_components&quot;&gt;wrote about testing UI components&lt;/a&gt;, and why I
recommend that you don&#39;t use snapshots. I finished that article with this line:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your tests should give me the confidence to refactor any component to your
heart&#39;s content. They should fail if you change functionality, not structure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Instead, I advocate for writing entirely
&lt;a href=&quot;https://en.wikipedia.org/wiki/Functional_testing&quot;&gt;functional tests&lt;/a&gt;, asserting
based on the required functionality of the component.&lt;/p&gt;
&lt;p&gt;This type of testing is certainly more difficult and time-consuming (especially
compared to snapshots). But I think the benefits are clear: they hold up under
&lt;strong&gt;refactoring&lt;/strong&gt;, promote &lt;strong&gt;iteration&lt;/strong&gt;, and gives you the confidence to
&lt;strong&gt;grow&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;refactoring&quot; tabindex=&quot;-1&quot;&gt;Refactoring&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/free-to-grow-with-tests/#refactoring&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Refactoring”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I have yet to come across a component or complex function I&#39;ve written that
couldn&#39;t use refactoring. Maybe it&#39;s a new technique that is perfect for these
situation, or perhaps it&#39;s logic that appeared logical at the time that isn&#39;t on
a second look.&lt;/p&gt;
&lt;p&gt;Whatever the case, refactoring code is a constant in this profession, and tests
(should) help you embrace it.&lt;/p&gt;
&lt;p&gt;When you write a functional test, you start with a statement like &amp;quot;With &lt;code&gt;A&lt;/code&gt;
input, my function should output &lt;code&gt;B&lt;/code&gt;.&amp;quot; Then you write a test that covers that
condition. Your test doesn&#39;t care how you get from &lt;code&gt;A&lt;/code&gt; to &lt;code&gt;B&lt;/code&gt;, just that you
always do.&lt;/p&gt;
&lt;p&gt;Maybe the first time through you take a long an circuitous path with lots of
conditional logic. Next time you refactor, you take a more direct route. Then
you decide that some of those conditions were necessary. The test doesn&#39;t care,
so long as &lt;code&gt;fn(A) = B&lt;/code&gt;.&lt;/p&gt;
&lt;!-- &lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Refactoring ones own code, and watching the tests continue to pass, is both a humbling and an enriching experience.&lt;/p&gt;&amp;mdash; Venkat Subramaniam (@venkat_s) &lt;a href=&quot;https://twitter.com/venkat_s/status/1176386197641412608?ref_src=twsrc%5Etfw&quot;&gt;September 24, 2019&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt; --&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;iteration&quot; tabindex=&quot;-1&quot;&gt;Iteration&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/free-to-grow-with-tests/#iteration&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Iteration”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Refactoring is looking back at code, while iterating is looking ahead. Our goal
as software engineers should be to continuously deliver incremental improvements
on our active products. This means slowing building on what we already have.&lt;/p&gt;
&lt;p&gt;Maybe you designed a function with situation A in mind, but notice that with a
minor adjustment it can easily handle B and C. Once you are done making that
change, the functional test that you wrote for situation A should be the
barometer for moving forward.&lt;/p&gt;
&lt;p&gt;If the test passes, then you&#39;re good to proceed. If not, then you&#39;ve made a
breaking change; go back and rethink your approach.&lt;/p&gt;
&lt;p&gt;When you&#39;re looking to add a new feature to your product, a passing test suite
should give you full confidence that all of your changes are backwards
compatible.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;free-to-grow&quot; tabindex=&quot;-1&quot;&gt;Free to grow&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/free-to-grow-with-tests/#free-to-grow&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Free to grow”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;A redwood tree doesn&#39;t grow to 300 feet over night. Rather, a journey of a
thousand miles begins with a single step&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/free-to-grow-with-tests/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Great software is not written in one sitting. It is fine tuned and improved
slowly over the lifespan of the product.&lt;/p&gt;
&lt;p&gt;This means a regular cycle of refactoring and iteration–improving and expanding.
The more your software is able to do this, the healthier it is and the better it
will become over time.&lt;/p&gt;
&lt;p&gt;A functional test suite enables and encourages your software to grow this way.
You can make improvements to your code and verify that it still functions. You
can add more features while being assured that there are no breaking changes.&lt;/p&gt;
&lt;p&gt;To set your team or product up on a thousand-mile journey, start with your best
foot forward. Write the kind of tests that enable you to take each successive
step with confidence.&lt;/p&gt;
&lt;p&gt;Write functional tests.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Paraphrased from Laozi&#39;s
&lt;a href=&quot;https://en.wikipedia.org/wiki/Tao_Te_Ching&quot;&gt;&lt;em&gt;Tao Te Ching&lt;/em&gt;&lt;/a&gt; &lt;a href=&quot;https://seanmcp.com/articles/free-to-grow-with-tests/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 17 Feb 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/free-to-grow-with-tests/</guid>
    </item>
    <item>
      <title>How to check npm scripts in current directory</title>
      <link>https://seanmcp.com/articles/check-npm-scripts-in-current-directory/</link>
      <description>&lt;p&gt;As a front-end engineer, I spend a lot of time jumping in-between JavaScript
projects. Often times I want to run a command from those projects to start
watchmode or spin up a service.&lt;/p&gt;
&lt;p&gt;The commands that I want to use are in the &lt;code&gt;package.json&lt;/code&gt; under &lt;code&gt;&amp;quot;scripts&amp;quot;&lt;/code&gt;.
When I haven&#39;t memorized the common commands, I need to either open the file in
my editor or use a Unix utility like &lt;code&gt;cat&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# In my editor&lt;/span&gt;
code package.json

&lt;span class=&quot;token comment&quot;&gt;# In the terminal&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; package.json&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both of these commands work, but they are slow. &lt;code&gt;package.json&lt;/code&gt; files can be
massive, including dozens of dependencies, dev depenendencies, and other fields.
To find the scripts, I need to sort through the cruft to find the information
that I want. This isn&#39;t very efficient.&lt;/p&gt;
&lt;p&gt;Instead, I wrote a short bash scripts to quickly do the work for me. Here is the
code in all of its glory:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;package.json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-pe&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;JSON.parse(require(&#39;fs&#39;).readFileSync(&#39;package.json&#39;).toString()).scripts&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;There is no &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;package.json&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; in this directory&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, I let the computer know to run this file with bash. Then I set up an &lt;code&gt;if&lt;/code&gt;
block: if there is a &lt;code&gt;package.json&lt;/code&gt; file in this directory, then run the
following code; if not, then print a &amp;quot;can&#39;t find it&amp;quot; message.&lt;/p&gt;
&lt;p&gt;The code to run, inspired by
&lt;a href=&quot;https://stackoverflow.com/questions/1955505/parsing-json-with-unix-tools#comment36088507_18469304&quot;&gt;a StackOverflow comment&lt;/a&gt;,
is a node process with two flags:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-e&lt;/code&gt; tells node to evaluate the script that you pass&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; tells node to print the results to the console&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Within the script, I am using &lt;code&gt;JSON&lt;/code&gt; to parse the results of a
&lt;code&gt;fs.readFileSync()&lt;/code&gt; of the &lt;code&gt;package.json&lt;/code&gt;, then diving down to the &lt;code&gt;scripts&lt;/code&gt;
key.&lt;/p&gt;
&lt;p&gt;I set it up by running &lt;code&gt;chmod&lt;/code&gt; with two flags on the file in a &lt;code&gt;scripts/&lt;/code&gt;
directory:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; u+x ~/scripts/npm-scripts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I could resource my terminal and run the command with &lt;code&gt;npm-scripts&lt;/code&gt;. Bish
bash bosh.&lt;/p&gt;
&lt;p&gt;Everything worked fine, but I wanted an easier way to share my script with
others. The &lt;code&gt;chmod&lt;/code&gt; command and flags are hard to remember, so it would be
easier if the script could be compressed into a one-liner that could be aliased
in their &lt;code&gt;~/.bash_profile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To do that, I removed all the new lines and added semicolons to separate the
statements. The alias needed to be wrapped in quotes, so I escaped all the
double quotes within the script.&lt;/p&gt;
&lt;p&gt;Now I had a handy alias to share:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;if [[ -f &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;package.json&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt; ]]; then node -pe &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;JSON.parse(require(&#39;fs&#39;).readFileSync(&#39;package.json&#39;).toString()).scripts&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;; else echo &lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;There is no package.json in this directory&lt;span class=&quot;token entity&quot; title=&quot;&#92;&amp;quot;&quot;&gt;&#92;&quot;&lt;/span&gt;; fi&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Overall, I&#39;m pretty happy with this utility. Going forward, I would like to
extend it so that you can lookup and key on &lt;code&gt;package.json&lt;/code&gt; by passing an
argument.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;update-%E2%80%93-apr-4%2C-2020&quot; tabindex=&quot;-1&quot;&gt;Update – Apr 4, 2020&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/check-npm-scripts-in-current-directory/#update-%E2%80%93-apr-4%2C-2020&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Update – Apr 4, 2020”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I created a new script to which you could pass an argument to pick a key from
the &lt;code&gt;package.json&lt;/code&gt;. This script is in zsh, but I think it ports to bash:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# rpj - Read package.json&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function-name function&quot;&gt;rpj&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;package.json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-pe&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;JSON.parse(require(&#39;fs&#39;).readFileSync(&#39;package.json&#39;).toString())[&#39;&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;&#39; || &#39;scripts&#39;]&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;There is no &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;package.json&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; in this directory&quot;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note how the shell arguments need to be wrapped in &lt;code&gt;&#39;&#39;&lt;/code&gt; in order to work.
Otherwise JavaScript thinkgs that it is looking for a variable, which is
undefined.&lt;/p&gt;
&lt;p&gt;If no argument is provided, then it falls back to printing the scripts which is
probably the most common use case for me.&lt;/p&gt;
&lt;p&gt;I also named the new function &lt;code&gt;rpj&lt;/code&gt; for &amp;quot;Read &lt;code&gt;package.json&lt;/code&gt;&amp;quot; to avoid any
&lt;a href=&quot;https://en.wikipedia.org/wiki/Name_server&quot;&gt;confusion with name servers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the next iteration, I would like to handle errors, but that is a project for
another day.&lt;/p&gt;
</description>
      <pubDate>Thu, 06 Feb 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/check-npm-scripts-in-current-directory/</guid>
    </item>
    <item>
      <title>How to remove duplicates from an object array?</title>
      <link>https://seanmcp.com/articles/remove-duplicates-from-object-array/</link>
      <description>&lt;p&gt;Reviewing a recent code exercise at work, we came across a situation where a
candidate wanted to ensure that there were no duplicates in an array of objects.&lt;/p&gt;
&lt;p&gt;The solution, which seemed to have been cobbled together from
&lt;a href=&quot;https://stackoverflow.com/questions/2218999/remove-duplicates-from-an-array-of-objects-in-javascript&quot;&gt;suggestions in this Stack Overflow thread&lt;/a&gt;,
included &lt;code&gt;Array.from()&lt;/code&gt;, &lt;code&gt;new Set&lt;/code&gt;, &lt;code&gt;Array.map()&lt;/code&gt;, and &lt;code&gt;Array.find()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It worked, but it definitely fulfilled the definition of
&lt;a href=&quot;https://www.urbandictionary.com/define.php?term=Frankencode&quot;&gt;&amp;quot;frankencode&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&#39;s look at a simpler solution to this common problem with
&lt;a href=&quot;https://en.wikipedia.org/wiki/Big_O_notation&quot;&gt;a simple &lt;em&gt;O(n)&lt;/em&gt; complexity&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;setup&quot; tabindex=&quot;-1&quot;&gt;Setup&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-duplicates-from-object-array/#setup&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Setup”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The data here could be pretty complicated, so I&#39;m going to reduce it to the
simplest form. We have an array of possibly duplicate objects, and we&#39;ll know
that they&#39;re duplicated based on the &lt;code&gt;name&lt;/code&gt; key:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; listWithDups &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;one&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;two&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;one&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &amp;lt;-- Duplicate&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;three&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want to be able to loop through this data as few times as possible in order
to remove that duplicate entry.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;steps&quot; tabindex=&quot;-1&quot;&gt;Steps&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-duplicates-from-object-array/#steps&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Steps”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;There are a few things that we are going to need in order to solve this problem.
First, we&#39;re going to need a new array to which we&#39;ll add unique items. Second,
we&#39;re going to need a way to keep track of the items that we have already seen.
And third, we&#39;re going to need a way to iterate through the data.&lt;/p&gt;
&lt;p&gt;Let&#39;s look at those one at a time.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;new-array&quot; tabindex=&quot;-1&quot;&gt;New array&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-duplicates-from-object-array/#new-array&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “New array”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;For this process, we want this to create a new unique array without modifying
the original. This is a good practice, because it gives you the ability to
compare your data down the road.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; uniqueList &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we are iterating through our original array and come across a unique
object, we&#39;ll add it to &lt;code&gt;uniqueList&lt;/code&gt; with &lt;code&gt;Array.push()&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;unique-key-tracker&quot; tabindex=&quot;-1&quot;&gt;Unique key tracker&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-duplicates-from-object-array/#unique-key-tracker&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Unique key tracker”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In order to know if an object is unique, we need to know all of the keys that we
have seen before.&lt;/p&gt;
&lt;p&gt;There are a few different data types that we could use, but the best option here
is an object; they&#39;re perfect for looking up information based on a known key.&lt;/p&gt;
&lt;p&gt;This object only exists to track those keys. It will not be returned and no
other process depends on its information. That makes it a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Temporary_variable&quot;&gt;temporary variable&lt;/a&gt;, and we
should name it as such:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; temp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For every object in our list, we&#39;ll check to see if their &lt;code&gt;name&lt;/code&gt; key exists on
our temp object. If it does not, then we&#39;ll add it to the object and then add
the object to the unique list. If it does not, then we know that it is a
duplicate and can move on.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;iterate&quot; tabindex=&quot;-1&quot;&gt;Iterate&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-duplicates-from-object-array/#iterate&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Iterate”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Since we are going to be iterating through data, the easiest&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/remove-duplicates-from-object-array/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; way to do that
is with a &lt;code&gt;for&lt;/code&gt; loop. We&#39;re going to use a
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of&quot;&gt;&lt;code&gt;for...of&lt;/code&gt;&lt;/a&gt;
here because we don&#39;t care about the index number:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; item &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; listWithDups&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// TODO: Check if item is unique.&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// If so, add it to the list and remember it&#39;s name.&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// If not, pass over; it&#39;s a duplicate.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can go about implementing the steps above.&lt;/p&gt;
&lt;p&gt;Since we&#39;re using our &lt;code&gt;temp&lt;/code&gt; object to track all of the items that we have
already encountered, we can check to see if each item&#39;s &lt;code&gt;name&lt;/code&gt; exists as a key
on &lt;code&gt;temp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note: We haven&#39;t written the logic to add items to &lt;code&gt;temp&lt;/code&gt; yet, but we know that
this is how we want the application to work.&lt;/p&gt;
&lt;!-- ```js/2 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; item &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; listWithDups&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// If we haven&#39;t seen this name before...&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;temp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within this &lt;code&gt;if&lt;/code&gt; block, we&#39;ll do our &amp;quot;unique name&amp;quot; logic. We want to add the
item to our unique list and remember the name for next time.&lt;/p&gt;
&lt;!-- ```js/3-4 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; item &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; listWithDups&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// If we haven&#39;t seen this name before...&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;temp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    uniqueItems&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Add to unique list&lt;/span&gt;
    temp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Remember the name&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that loop has run, we will have built our &lt;code&gt;uniqueItems&lt;/code&gt; array without
duplicating any values. We have successfully de-duped our array with only a
single iteration!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;sample&quot; tabindex=&quot;-1&quot;&gt;Sample&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/remove-duplicates-from-object-array/#sample&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Sample”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Here is a Repl of the solution. Feel free to fork it, make improvements, and
&lt;a href=&quot;https://seanmcp.com/articles/remove-duplicates-from-object-array/#comment-link&quot;&gt;share your code with me&lt;/a&gt;.&lt;/p&gt;
&lt;iframe height=&quot;400px&quot; width=&quot;100%&quot; src=&quot;https://repl.it/@SeanMcP/Unique-items-in-array?lite=true&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot; sandbox=&quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;YMMV &lt;a href=&quot;https://seanmcp.com/articles/remove-duplicates-from-object-array/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 03 Feb 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/remove-duplicates-from-object-array/</guid>
    </item>
    <item>
      <title>Write a draft script for your SSG blog</title>
      <link>https://seanmcp.com/articles/write-a-draft-script-for-your-ssg-blog/</link>
      <description>&lt;p&gt;This site is powered by Eleventy, a simple static-site generator. All of the
pages and articles exists as markdown files that are converted into HTML files
via Nunjuck templates at build time.&lt;/p&gt;
&lt;p&gt;For a blogging platform, it&#39;s pretty neat. I enjoy being able to run the whole
site from the comfort of my text editor and the command line (with a little help
from Netlify for continual deployments).&lt;/p&gt;
&lt;p&gt;The secret sauce behind markdown-based sites is the frontmatter: specially
formatted content at the top of a markdown file that is read by the generator.
Here&#39;s what the frontmatter for a typical article looks like:&lt;/p&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@layouts/ArticleLayout.astro&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add event listener for class change
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  How to create a custom event listener for class names using the
  MutationObserver API
&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2019-05-10&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; JavaScript
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; Web&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Start writing your article here --&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When I want to write a new article, I need to make sure I have all of those
fields populated in a particular way in order for Eleventy to generate the page
correctly.&lt;/p&gt;
&lt;p&gt;Formatting and required fields are not something that I care to remember, so I
wanted to develop an easier method for generating a draft for this blog. This is
my journey.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;setup&quot; tabindex=&quot;-1&quot;&gt;Setup&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/write-a-draft-script-for-your-ssg-blog/#setup&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Setup”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Most static-site generators will have a directory for you to store some files
that are excluded from the build process. For Eleventy, that default directory
is &lt;code&gt;_includes/&lt;/code&gt;. I added a subdirectory for &lt;code&gt;templates/&lt;/code&gt; and added an
&lt;code&gt;article.md&lt;/code&gt;. All it contains is the bare-bones frontmatter for a new article:&lt;/p&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;span class=&quot;token front-matter-block&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token front-matter yaml language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token datetime number&quot;&gt;2020-01-01&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; SAMPLE_TAG&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hard coded the date because I have a hard time remembering the YYYY-MM-DD
format. It would be cool for the script to generate that for me.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;solution-1%3A-bash-script&quot; tabindex=&quot;-1&quot;&gt;Solution 1: Bash script&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/write-a-draft-script-for-your-ssg-blog/#solution-1%3A-bash-script&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Solution 1: Bash script”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Now that I have a template to reference, all I really need to do is write a
simple script to copy that file to the &lt;code&gt;articles/&lt;/code&gt; directory. I added the
following code to a &lt;code&gt;create-draft.sh&lt;/code&gt; file in the root directory:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class=&quot;token assign-left variable&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;draft

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token assign-left variable&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;_includes/templates/article.md&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;articles/_&lt;span class=&quot;token variable&quot;&gt;$title&lt;/span&gt;.md&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script declares a variable &lt;code&gt;title&lt;/code&gt; and sets the value to the string
&lt;code&gt;&amp;quot;draft&amp;quot;&lt;/code&gt;. Then it checks to see if another argument is passed. If so, then it
reassigns &lt;code&gt;title&lt;/code&gt; to that value.&lt;/p&gt;
&lt;p&gt;Then it copies the article template to the &lt;code&gt;articles/&lt;/code&gt; directory with the
filename title.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I am prepending an underscore to the name of the file because I have
configured Eleventy to ignore markdown files that begin with an underscore from
the build.
&lt;a href=&quot;https://github.com/11ty/eleventy/issues/188#issuecomment-488350222&quot;&gt;The solution got Eleventy&#39;s stamp of approval.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I added a &lt;code&gt;draft&lt;/code&gt; script to packages.json:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;draft&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sh create-draft.sh&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that was in place, I could call my script by running:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm run draft my-new-article
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This worked, but it was pretty simple. I needed to remember to use kebab case
for the title of the article so that the file name would work. It didn&#39;t add the
title to the copied file, nor set a date.&lt;/p&gt;
&lt;p&gt;It served me well for a while, but eventually time came for a change.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;solution-2%3A-node.js-script&quot; tabindex=&quot;-1&quot;&gt;Solution 2: node.js script&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/write-a-draft-script-for-your-ssg-blog/#solution-2%3A-node.js-script&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Solution 2: node.js script”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;To be fair, the original bash script could have been improved to meet all of my
needs. But I&#39;m not as comfortable with Bash as I am with JavaScript, and I jump
at every opportunity to work in node.js.&lt;/p&gt;
</description>
      <pubDate>Fri, 31 Jan 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/write-a-draft-script-for-your-ssg-blog/</guid>
    </item>
    <item>
      <title>What default parameters do (and don&#39;t do)</title>
      <link>https://seanmcp.com/articles/what-default-parameters-do-and-dont-do/</link>
      <description>&lt;p&gt;Default parameters are a handy feature in JavaScript.
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters&quot;&gt;MDN has a more thorough explanation&lt;/a&gt;,
but imagine a function that greets a user:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;greetUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we call our function and pass a name, we get the expected log:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;greetUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Abby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Hello Abby!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what about when we don&#39;t pass a name? &lt;strong&gt;Quiz time&lt;/strong&gt;: What is going to log?&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;greetUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Hello undefined!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Is that what you expected? Since we passed no argument, the &lt;code&gt;name&lt;/code&gt; parameter is
&lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;JavaScript — ever the helpful friend — sees that we want to include that value
in a string, so it
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Type_coercion&quot;&gt;coerces it into the correct type&lt;/a&gt;,
and then logs it.&lt;/p&gt;
&lt;p&gt;You probably don&#39;t want your function to return &lt;code&gt;Hello undefined!&lt;/code&gt;, so let&#39;s try
a default parameter.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;what-default-parameters-do&quot; tabindex=&quot;-1&quot;&gt;What default parameters do&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/what-default-parameters-do-and-dont-do/#what-default-parameters-do&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “What default parameters do”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Add the following to the declaration line of &lt;code&gt;greetUser()&lt;/code&gt;:&lt;/p&gt;
&lt;!-- ```js/0 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;greetUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;there&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we&#39;re saying to our function, &amp;quot;if you don&#39;t receive an argument, set the
value of the &lt;code&gt;name&lt;/code&gt; parameter to be &lt;code&gt;&amp;quot;there&amp;quot;&lt;/code&gt;.&amp;quot; When we call our function and
pass an argument, we get the same result:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;greetUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Abby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Hello Abby!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, when we call this updated function without passing an argument, the
default parameter kicks in:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;greetUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Hello there!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bingo! Now if our function is called without an argument, then the resulting log
still makes sense.&lt;/p&gt;
&lt;p&gt;In this situation, the default parameter is working as a fallback value. This is
probably the most common use case. But you will also find default parameters
useful to reduce existential checking.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;reduce-checks&quot; tabindex=&quot;-1&quot;&gt;Reduce checks&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/what-default-parameters-do-and-dont-do/#reduce-checks&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Reduce checks”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Imagine a user object with a &lt;code&gt;name&lt;/code&gt; key that we want to log. In order to update
our original function to handle this use case, I might do something like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;greetUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello there!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can imagine the complexity of this dive check growing with the size of the
user object. Instead, we can save ourselves some trouble by defaulting that
parameter to something that we can use right away:&lt;/p&gt;
&lt;!-- ```js/0 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;greetUser&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;there&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We set the default value of the &lt;code&gt;user&lt;/code&gt; parameter to be an object with a &lt;code&gt;name&lt;/code&gt;
key that we could access.&lt;/p&gt;
&lt;p&gt;I use this pattern often; default props make it easier to see what types and
shapes of arguments that any given function or component is expecting.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;what-default-parameters-don&#39;t-do&quot; tabindex=&quot;-1&quot;&gt;What default parameters don&#39;t do&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/what-default-parameters-do-and-dont-do/#what-default-parameters-don&#39;t-do&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “What default parameters don&#39;t do”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;A parameter will only default to a given value if it the argument passed is
&lt;code&gt;undefined&lt;/code&gt;&lt;/strong&gt;. So either no argument is passed, or the function specifically
receives &lt;code&gt;undefined&lt;/code&gt; as an argument.&lt;/p&gt;
&lt;p&gt;When I first learned about default parameters, I developed the wrong mental
model — associating them with falsy values in JavaScript. My incorrect thinking
went like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When ever I pass an argument that evaluates to false, the default parameter
will kick in and save me from errors! &lt;br&gt;— Sean, being wrong&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I ran into this problem at work when I expected a function to return the default
parameter when passed a &lt;code&gt;null&lt;/code&gt; argument.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;favoriteAnimal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;animal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;wolf&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Favorite animal:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; animal&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;favoriteAnimal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;manatee&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Favorite animal: manatee&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;favoriteAnimal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Favorite animal: wolf&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;favoriteAnimal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Favorite animal: null&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s because &lt;code&gt;null&lt;/code&gt; is a deliberately passed value (even if I didn&#39;t know that
I was deliberately passing it). Default parameters will only kick in if that
argument is omitted or passed as &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To state it plainly: &lt;strong&gt;falsy values do NOT become default parameters&lt;/strong&gt;. It only
works for &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So the above code is worked as designed, even if it&#39;s not what I expected. Time
to update that mental model!&lt;/p&gt;
&lt;p&gt;Hopefully that clears up the mystery of default parameters for you. Happy
coding!&lt;/p&gt;
</description>
      <pubDate>Mon, 13 Jan 2020 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/what-default-parameters-do-and-dont-do/</guid>
    </item>
    <item>
      <title>&quot;Stop Teaching Code&quot; in JavaScript</title>
      <link>https://seanmcp.com/articles/stop-teaching-code-resources/</link>
      <description>&lt;p&gt;At some time in the future, I would like to return to the classroom to teach
programming to middle school students. That is the age when I first starting
coding, and I would love the opportunity to inspire the next generation of
developers at an early age.&lt;/p&gt;
&lt;p&gt;So I&#39;m on the lookout for good techniques, strategies, and patterns for teaching
the basics of computer science. &lt;a href=&quot;https://seanmcp.com/articles/stop-teaching-code-resources/#comment-link&quot;&gt;Hit me up if you have any&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Today I read
&lt;a href=&quot;https://blog.upperlinecode.com/stop-teaching-code-a1039983b39&quot;&gt;&amp;quot;Stop Teaching Code&amp;quot; by Jeff Olson&lt;/a&gt;
where he described a different approach to teaching programming. He advocated
for ditching the definitions, unrealistic examples, and non-sensical names and
use real-world puzzles for students to solve.&lt;/p&gt;
&lt;p&gt;It&#39;s an interesting read, and I recommend it if you have any dreams of teaching
programming.&lt;/p&gt;
&lt;p&gt;All of the examples in Olson&#39;s article are in Python, but I plan on introducing
students to code with JavaScript. So here are all of the examples from his
article rewritten in JavaScript:&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;translated-examples&quot; tabindex=&quot;-1&quot;&gt;Translated Examples&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/stop-teaching-code-resources/#translated-examples&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Translated Examples”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Note: I&#39;ve linked to the nearest anchor on Medium, but they appear to be
generated and might change. Your mileage may vary.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;1.-code-for-predictions&quot; tabindex=&quot;-1&quot;&gt;1. &lt;a href=&quot;https://blog.upperlinecode.com/stop-teaching-code-a1039983b39#511e&quot;&gt;Code for Predictions&lt;/a&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/stop-teaching-code-resources/#1.-code-for-predictions&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “1. Code for Predictions”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Tamara&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;2.-example-1%3A-conditionals&quot; tabindex=&quot;-1&quot;&gt;2. &lt;a href=&quot;https://blog.upperlinecode.com/stop-teaching-code-a1039983b39#0f1e&quot;&gt;Example 1: Conditionals&lt;/a&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/stop-teaching-code-resources/#2.-example-1%3A-conditionals&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “2. Example 1: Conditionals”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; age &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;age &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;You&#39;re old enough to buy a ticket for an R-rated film.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;You&#39;ll be old enough in &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;18&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; age&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; years&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;3.-example-2%3A-collections&quot; tabindex=&quot;-1&quot;&gt;3. &lt;a href=&quot;https://blog.upperlinecode.com/stop-teaching-code-a1039983b39#147c&quot;&gt;Example 2: Collections&lt;/a&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/stop-teaching-code-resources/#3.-example-2%3A-collections&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “3. Example 2: Collections”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; favorite_foods &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Sushi&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Tamales&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mofongo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pizza&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Chicken Tikka&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;favorite_foods&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;3.-example-3%3A-objects&quot; tabindex=&quot;-1&quot;&gt;3. &lt;a href=&quot;https://blog.upperlinecode.com/stop-teaching-code-a1039983b39#d814&quot;&gt;Example 3: Objects&lt;/a&gt;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/stop-teaching-code-resources/#3.-example-3%3A-objects&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “3. Example 3: Objects”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; user1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Ty&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Tdog@aol.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Pa$$word&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; user2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Sarai&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SMendes@hotmail.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Kangaroo!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; user3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Osu&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Osu22@gmail.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;12345abcde&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;age&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;p&gt;I hope that helps. Happy coding!&lt;/p&gt;
</description>
      <pubDate>Tue, 26 Nov 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/stop-teaching-code-resources/</guid>
    </item>
    <item>
      <title>5 Lessons from 10k open-source downloads</title>
      <link>https://seanmcp.com/articles/5-lessons-from-10k-open-source-downloads/</link>
      <description>&lt;p&gt;In April of 2018, I wrote an article
&lt;a href=&quot;https://medium.com/@seanmcp/%EF%B8%8F-how-to-use-emojis-in-react-d23bbf608bf7&quot;&gt;&amp;quot;How to use emojis in React&amp;quot;&lt;/a&gt;.
At the time, the default eslint configuration for Create React App would flash
an error if you put an emoji in a rendered string.&lt;/p&gt;
&lt;p&gt;The answer was to wrap the emoji in a &lt;code&gt;span&lt;/code&gt; with some appropriate attributes to
notify screen readers that it was being used as an image. Since it was React
specific, I included a component that handles all the attribute logic for you.&lt;/p&gt;
&lt;p&gt;The article gained some traction and, thanks to Medium&#39;s SEO, remains the first
page on
&lt;a href=&quot;https://www.google.com/search?q=use+emojis+in+react&amp;amp;oq=how+to+use+emojis+in+react&quot;&gt;a Google search for &amp;quot;use emojis react&amp;quot;&lt;/a&gt;.
Later that same year, I decided to create and release a package for the included
React component. Thus, &lt;a href=&quot;https://npm.im/a11y-react-emoji&quot;&gt;&lt;code&gt;a11y-react-emoji&lt;/code&gt;&lt;/a&gt; was
born.&lt;/p&gt;
&lt;p&gt;Twelve months and 17 versions later, and my little package has
&lt;a href=&quot;https://www.npmjs.com/package/a11y-react-emoji&quot;&gt;10,000 downloads from the npm registry&lt;/a&gt;.
Beyond that, the repo has
&lt;a href=&quot;https://github.com/SeanMcP/a11y-react-emoji&quot;&gt;15 stars on GitHub&lt;/a&gt; and is used by
&lt;a href=&quot;https://github.com/SeanMcP/a11y-react-emoji/network/dependents?package_id=UGFja2FnZS0yODIxNzMzNDE%3D&quot;&gt;61 other projects&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There have been some maintainer highs and lows in that time, so here are the
five biggest lessons I learned along the way.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;1.-packages-can-be-simple&quot; tabindex=&quot;-1&quot;&gt;1. Packages can be simple&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/5-lessons-from-10k-open-source-downloads/#1.-packages-can-be-simple&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “1. Packages can be simple”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Before stepping into the world of open source, I thought of packages as a black
box. But I&#39;ve since learned that they are much simpler than they appear.&lt;/p&gt;
&lt;p&gt;In the JavaScript world, a package is just four files:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;package.json&lt;/code&gt; with a few fields,&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;index.js&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;README.md&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;and a &lt;code&gt;LICENSE&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And the last two are optional. Once I got over the hurdle of
&lt;a href=&quot;https://www.freecodecamp.org/news/how-to-make-a-beautiful-tiny-npm-package-and-publish-it-2881d4307f78/&quot;&gt;publishing my first package&lt;/a&gt;,
the curtain of mystery fell away.&lt;/p&gt;
&lt;p&gt;Take a moment and look through the &lt;code&gt;node_modules/&lt;/code&gt; of you next project, and
you&#39;ll see a bunch of directories with those files mentioned above. Not too
scary!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;2.-dependencies-can-get-tricky&quot; tabindex=&quot;-1&quot;&gt;2. Dependencies can get tricky&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/5-lessons-from-10k-open-source-downloads/#2.-dependencies-can-get-tricky&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “2. Dependencies can get tricky”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;If you&#39;re publishing a basic utility, you may not need to worry about
dependencies. But the more complex your library becomes, the more tricky it
becomes to manage your dependencies.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;a11y-react-emoji&lt;/code&gt; was a shared React component written in TypeScript, which
meant I needed to manage React and TypeScript dependencies. I wanted the
component to be fully tested, so add Jest and Babel to the mix. Error checking?
Add ESLint. Consistent formatting? Bring Prettier along.&lt;/p&gt;
&lt;p&gt;Before long, your dependency tree can grow really big. Keep something in mind
when creating a package: every dependency you add is another dependency that you
have to be willing to manage. That can add a maintenance work to your package.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;3.-security-is-a-hassle&quot; tabindex=&quot;-1&quot;&gt;3. Security is a hassle&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/5-lessons-from-10k-open-source-downloads/#3.-security-is-a-hassle&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “3. Security is a hassle”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I&#39;m not an expert on security. So when GitHub flags one of my packages for
potential security risks, I still feel a chill run down my spine.&lt;/p&gt;
&lt;p&gt;When I first created the &lt;code&gt;a11y-react-emoji&lt;/code&gt;, I was quick to address every
security risk highlight, merge the changes, and release a new version of the
package. Every time it felt like I was just a few clicks in front of the next
Equifax data breach.&lt;/p&gt;
&lt;p&gt;But after a few months at the helm, I stopped caring so much. Part of that is
how the project is structured: &lt;code&gt;a11y-react-emoji&lt;/code&gt; has no dependencies, which
means that no flagged security issues present a risk in production.&lt;/p&gt;
&lt;p&gt;Every potential issue is within the dev dependency tree, which isn&#39;t a big deal
to the package user.&lt;/p&gt;
&lt;p&gt;However, keeping a large-scale library with tons of dependency ahead of all
security risks would be a nightmare. That&#39;s not something I&#39;m chomping at the
bit to do in my spare time.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;4.-leverage-the-community&quot; tabindex=&quot;-1&quot;&gt;4. Leverage the community&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/5-lessons-from-10k-open-source-downloads/#4.-leverage-the-community&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “4. Leverage the community”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Earlier this year,
&lt;a href=&quot;https://github.com/SeanMcP/a11y-react-emoji/issues/3&quot;&gt;@bdbaraban filed an issue&lt;/a&gt;
with &lt;code&gt;a11y-react-emoji&lt;/code&gt; concerning its types. I was just learning TypeScript
when I wrote the library, and his suggestion was an improvement to the existing
code.&lt;/p&gt;
&lt;p&gt;I asked him if he wanted to open a pull request to make the change but quickly
got antsy and did it myself.&lt;/p&gt;
&lt;p&gt;That was a mistake. The beauty of open-source is the community; it&#39;s the product
of our collective intelligence. It didn&#39;t matter that the current types for the
package were limited. What would have been more important would be to wait and
give someone else the opportunity to contribute.&lt;/p&gt;
&lt;p&gt;To encourage more community involvement, you should include the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An
&lt;a href=&quot;https://help.github.com/en/github/building-a-strong-community/manually-creating-a-single-issue-template-for-your-repository&quot;&gt;&lt;code&gt;ISSUE_TEMPLATE.md&lt;/code&gt;&lt;/a&gt;
to standardize issues,&lt;/li&gt;
&lt;li&gt;labels for
&lt;a href=&quot;https://help.github.com/en/github/building-a-strong-community/helping-new-contributors-find-your-project-with-labels&quot;&gt;&lt;code&gt;good-first-issue&lt;/code&gt;&lt;/a&gt;
and &lt;a href=&quot;https://www.firsttimersonly.com/&quot;&gt;&lt;code&gt;first-timers-only&lt;/code&gt;&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;and contact information in the &lt;code&gt;README.MD&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When someone reaches out or files an issue, give them a few days to respond.
Security bugs should be fixed immediately; features and small fixes can wait.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;5.-don&#39;t-lose-yourself&quot; tabindex=&quot;-1&quot;&gt;5. Don&#39;t lose yourself&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/5-lessons-from-10k-open-source-downloads/#5.-don&#39;t-lose-yourself&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “5. Don&#39;t lose yourself”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;There is an undeniable high that comes from seeing your code used by someone
else in the wild or stars the project on GitHub. I&#39;m not immune; I&#39;ve found
myself getting caught up in that ever-growing download count since releasing the
package.&lt;/p&gt;
&lt;p&gt;It&#39;s important to remember that your worth is not determined by the number or
popularity of your open-source contributions. It has nothing to do with how many
Twitter followers you have, claps you&#39;ve received on Medium, or unique traffic
to your personal website.&lt;/p&gt;
&lt;p&gt;You are infinitely valuable for just being you.&lt;/p&gt;
&lt;p&gt;If you want to publish packages because you think it&#39;s fun or you want to help
other people, then open source is a great way to contribute. But don&#39;t lose
sight of that motivation.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I hope those were helpful. If you have any questions about open source or want
to share some tips of your own, &lt;a href=&quot;https://seanmcp.com/articles/5-lessons-from-10k-open-source-downloads/#comment-link&quot;&gt;please let me know&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Mon, 25 Nov 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/5-lessons-from-10k-open-source-downloads/</guid>
    </item>
    <item>
      <title>Should I snapshot my UI components?</title>
      <link>https://seanmcp.com/articles/snapshot-test-ui-components/</link>
      <description>&lt;p&gt;If you are writing tests for React components in 2019, you will probably find
your way to Airbnb&#39;s Enzyme testing utilities. The recent industry standard,
Enzyme provides you some useful tools for rendering your components.&lt;/p&gt;
&lt;p&gt;Often times, folks will turn to snapshot testing with Enzyme because it a) is
easy, b) provides significant test coverage, and c) seems like a good idea. I
worked for a company where the default test suite for any component was a
snapshot, then any additional tests were added to bump coverage to an acceptible
level.&lt;/p&gt;
&lt;p&gt;However, the ease of use is often a double-edged sword. Here I wanted to outline
some common issues that arise from using snapshot tests for your UI components.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;issue-%231%3A-false-positives&quot; tabindex=&quot;-1&quot;&gt;Issue #1: False positives&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/snapshot-test-ui-components/#issue-%231%3A-false-positives&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Issue #1: False positives”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;If you&#39;ve every worked in a codebase that snapshots UI components, you&#39;ll know:
snapshot tests fail all the time. This is because snapshots collect a JSON-ified
version of the shallow render from Enzyme. Whenever anything changes to the
structure of the render, the output is different and therefore the snapshot
fails.&lt;/p&gt;
&lt;p&gt;Whenever you need to refactor a component, you can be assured that the test will
fail because the new snapshot doesn&#39;t match the one on record.&lt;/p&gt;
&lt;p&gt;Because snapshot tests fail all the time, they become &lt;strong&gt;false positives&lt;/strong&gt;:
results which incorrectly indicate that a problem is present. You snapshot can
fail, even though everything about the component will still function as
expected.&lt;/p&gt;
&lt;p&gt;If your test can fail when the function still works, &lt;strong&gt;what value is the
snapshot test adding&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;I have seen deployments fail because the snapshot encountered an unexpected
&lt;code&gt;div&lt;/code&gt; tag. The &amp;quot;solution&amp;quot; was simple enough: update the snapshot and then deploy
again. But that has its own problems.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;issue-%232%3A-combating-false-positives&quot; tabindex=&quot;-1&quot;&gt;Issue #2: Combating false positives&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/snapshot-test-ui-components/#issue-%232%3A-combating-false-positives&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Issue #2: Combating false positives”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Since failing snapshot tests are so common, it is common to run you rest suite
with the &lt;code&gt;-u, --update-snapshot&lt;/code&gt; flag:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm run test -u
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This rewrites the snapshot to match the current value instead of comparing it to
the previous one. Since the updated snapshot will always match the new value,
the test passes. Running the update snapshot flag is kind of like doing this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; snapshot&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// npm test -u&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
snapshot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; snapshot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Passed!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a little silly, but I think it illustrates the point. On its own,
updating a snapshot will automatically pass a test without providing you any
valuable information.&lt;/p&gt;
&lt;p&gt;Since failing tests are so common, you will be tempted to add the updated
snapshot flag to every test run. I know that I got a little too quick the the
&lt;code&gt;-u&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;But as illustrated above, running updated snapshot tests provides no valuable
information. So if you need to update the snapshot test every time, &lt;strong&gt;what value
is the snapshot test adding&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;If you find yourself backed into this corner, take heart in knowing that it&#39;s
not your fault. Snapshot testing forces us to focus on structure.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;issue-%233%3A-structure-over-function&quot; tabindex=&quot;-1&quot;&gt;Issue #3: Structure over function&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/snapshot-test-ui-components/#issue-%233%3A-structure-over-function&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Issue #3: Structure over function”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Snapshot tests value the structure of a component over its functionality. They
don&#39;t tell you how the component will work in your application; it only tells
you how the JSX will look. So you need to ask yourself: Do I want my test suite
to care about the structure of my components?&lt;/p&gt;
&lt;p&gt;Let&#39;s imagine an &lt;code&gt;IconButton&lt;/code&gt; component that looks something like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IconButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; children&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; icon&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Icon icon&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;icon&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After reviewing with the design team, you determing that it would be better for
the button text to be inline with the &lt;code&gt;Icon&lt;/code&gt;, so you swap the &lt;code&gt;div&lt;/code&gt; for a
&lt;code&gt;span&lt;/code&gt;:&lt;/p&gt;
&lt;!-- ```js/4 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IconButton&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; children&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; icon&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Icon icon&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;icon&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this change, should the test for &lt;code&gt;IconButton&lt;/code&gt; fail? I&#39;d argue: no.&lt;/p&gt;
&lt;p&gt;The functionality of the IconButton hasn&#39;t changed; it still renders an &lt;code&gt;Icon&lt;/code&gt;
and passes the &lt;code&gt;onClick&lt;/code&gt; handler to the &lt;code&gt;button&lt;/code&gt; element. I and every developer
after me should be free to refactor as much as I need so long as the component
still functions in the same manner when we&#39;re done.&lt;/p&gt;
&lt;p&gt;But a snapshot test disagrees and will fail because you changed that tag. You
might anticipate the test failing and run it with the update snapshot flag,
which has all the problems listed above. So again, &lt;strong&gt;what value is the snapshot
test adding&lt;/strong&gt;?&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;snapshots-are-a-bad-fit-for-ui-testing&quot; tabindex=&quot;-1&quot;&gt;Snapshots are a bad fit for UI testing&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/snapshot-test-ui-components/#snapshots-are-a-bad-fit-for-ui-testing&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Snapshots are a bad fit for UI testing”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Shallow rendering + snapshot tests. &lt;a href=&quot;https://t.co/3TIa4VIhsc&quot;&gt;pic.twitter.com/3TIa4VIhsc&lt;/a&gt;&lt;/p&gt;&amp;mdash; Mark Dalgleish (@markdalgleish) &lt;a href=&quot;https://twitter.com/markdalgleish/status/1161616241531863045?ref_src=twsrc%5Etfw&quot;&gt;August 14, 2019&lt;/a&gt;&lt;/blockquote&gt; &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;In most instances, snapshots provde no additional value for your UI tests. They
are easy and feel good to write, but I think they add little confidence to your
testing suite for any given component.&lt;/p&gt;
&lt;p&gt;You may stumble across scenarios with a highly specialized component, definite
structure, and specific attributes that would benefit from a snapshot. But these
are an exception to the rule. In general, &lt;strong&gt;avoid snapshot testing for UI
components&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;another-way&quot; tabindex=&quot;-1&quot;&gt;Another way&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/snapshot-test-ui-components/#another-way&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Another way”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Instead of defaulting to snapshots, ask yourself: What does this component
&lt;strong&gt;need&lt;/strong&gt; to do? Then write a test that ensures the component can do just that.&lt;/p&gt;
&lt;p&gt;If you&#39;re working with Enzyme, use
&lt;a href=&quot;https://airbnb.io/enzyme/docs/api/ReactWrapper/find.html&quot;&gt;&lt;code&gt;find()&lt;/code&gt;&lt;/a&gt; to insure
that any necessary elements render with the appropriate attributes. Use
&lt;a href=&quot;https://airbnb.io/enzyme/docs/api/ReactWrapper/simulate.html&quot;&gt;&lt;code&gt;simulate()&lt;/code&gt;&lt;/a&gt; to
interact with your components in a meaningful way, focusing on functionality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Your tests should give me the confidence to refactor any component to your
heart&#39;s content&lt;/strong&gt;. They should fail if you change functionality, not structure.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;further-reading&quot; tabindex=&quot;-1&quot;&gt;Further reading&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/snapshot-test-ui-components/#further-reading&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Further reading”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kentcdodds.com/blog/testing-implementation-details&quot;&gt;&amp;quot;Testing Implementation Details&amp;quot; by Kent C. Dodds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://testing-library.com/docs/react-testing-library/intro&quot;&gt;React Testing Library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Wed, 11 Sep 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/snapshot-test-ui-components/</guid>
    </item>
    <item>
      <title>Edit a previous commit message</title>
      <link>https://seanmcp.com/articles/edit-previous-commit-message/</link>
      <description>&lt;p&gt;At my previous company, all commit messages need to begin with a ticket name and
number from Jira. If I&#39;m working on the Bananas project and am assigned ticket
5, my commit messages will look like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;BANANAS-5 Add user authentication
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you forget to add the ticket to the commit message, you are unable to push
your code to the project repository on BitBucket.&lt;/p&gt;
&lt;p&gt;Since I commit a lot outside of work and am the type of developer who makes
mistakes, I find myself with commit messages that are missing the required
ticket.&lt;/p&gt;
&lt;p&gt;You might not have the same policy on your project, but you may have found
yourself wanting to change a commit message. Here are two options for editing a
previous commit message.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;change-the-most-recent-commit&quot; tabindex=&quot;-1&quot;&gt;Change the most recent commit&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/edit-previous-commit-message/#change-the-most-recent-commit&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Change the most recent commit”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Sometimes you can catch the error quickly after making your commit. If you need
to change the most recent commit message, you can use the &lt;code&gt;amend&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;In your project directory in the terminal, enter:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git commit --amend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will bring the most recent commit message open in your default editor. Make
the necessary changes to the message, mind the formatting, save the file, and
exit. You should see a read out with the updated commit message.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;change-an-old-commit&quot; tabindex=&quot;-1&quot;&gt;Change an old commit&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/edit-previous-commit-message/#change-an-old-commit&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Change an old commit”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;More often than not, I don&#39;t find my commit message error until many commits
later. In those cases, the &lt;code&gt;amend&lt;/code&gt; flag won&#39;t help use. We need to &lt;code&gt;rebase&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Rebasing in git is a way to change commits from long ago by reapplying all the
commits from a point in time. When you &lt;code&gt;rebase&lt;/code&gt; you can rewrite the history of
your project; so proceed with caution.&lt;/p&gt;
&lt;p&gt;First, you need to find the commit message from which you want to start your
rebase. To do that, go to the log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now find find the commit &lt;strong&gt;immediately prior to the one you want to change&lt;/strong&gt; and
copy the hash (long series of letters and numbers). With that point of
reference, you&#39;re ready to rebase!&lt;/p&gt;
&lt;p&gt;Enter the &lt;code&gt;rebase&lt;/code&gt; command with the &lt;code&gt;interactive&lt;/code&gt; flag (you can also use &lt;code&gt;-i&lt;/code&gt;
for short) and the commit hash you copied:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git rebase --interactive &amp;lt;prior_commit_hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will open the default editor with a list of all the commits &lt;strong&gt;after&lt;/strong&gt; the
hash you provided. There is a good bit going on here, but don&#39;t be overwhelmed.
Focus on the top of where you can see a list of the commits and their messages.&lt;/p&gt;
&lt;p&gt;It should look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pick a8fc26a BANANAS-5 This is a good commit message
pick 60ac057 Change me!

# Rebase 5923966..60ac057 onto 5923966 (2 commands)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, find the commit message you want to change, and replace the word &lt;code&gt;pick&lt;/code&gt;
with &lt;code&gt;reword&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pick a8fc26a BANANAS-5 This is a good commit message
reword 60ac057 Change me!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then save and exit the editor.&lt;/p&gt;
</description>
      <pubDate>Fri, 23 Aug 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/edit-previous-commit-message/</guid>
    </item>
    <item>
      <title>Arguments or parameters?</title>
      <link>https://seanmcp.com/articles/arguments-or-parameters/</link>
      <description>&lt;p&gt;I have a hard time remembering the difference between two common programming
terms: arguments, and parameters.&lt;/p&gt;
&lt;p&gt;This simple inability leads to real insecurity when I speak with coworkers with
more education and experience. Nothing inspires imposter syndrome in a more than
not remembering the fundamentals!&lt;/p&gt;
&lt;p&gt;Here is the difference between the two similar terms:&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;arguments&quot; tabindex=&quot;-1&quot;&gt;Arguments&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/arguments-or-parameters/#arguments&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Arguments”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Arguments are the data passed to a function. Think of something simple like
&lt;code&gt;console.log()&lt;/code&gt;. In order to get a message written to the console, you need to
pass it some information.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;One&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every bit of information that you pass to a function is an argument. In the
above example, we are assigning four arguments to &lt;code&gt;console.log()&lt;/code&gt;: &lt;code&gt;&amp;quot;One&amp;quot;&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;,
&lt;code&gt;false&lt;/code&gt;, and &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;parameters&quot; tabindex=&quot;-1&quot;&gt;Parameters&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/arguments-or-parameters/#parameters&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Parameters”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Parameters are the data that a function is expecting. Let&#39;s say you have a
function that takes two numbers and returns the sum. It will look something like
this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The variables that a function is expecting are its parameters. In our &lt;code&gt;sum()&lt;/code&gt;
function, we are expecting two parameters: &lt;code&gt;a&lt;/code&gt;, and &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;remembering-the-difference&quot; tabindex=&quot;-1&quot;&gt;Remembering the difference&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/arguments-or-parameters/#remembering-the-difference&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Remembering the difference”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I&#39;ve been wracking my brain for a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Mnemonic&quot;&gt;mnemonic device&lt;/a&gt; for remembering the
difference, but have yet to come up with a great one. In the meantime, this will
have to do:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Arguments&lt;/strong&gt; are data you &lt;strong&gt;assign&lt;/strong&gt; to a function, while &lt;strong&gt;parameters&lt;/strong&gt; are
variables that the function is &lt;strong&gt;prepared&lt;/strong&gt; to accept.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If I hear of or come up with a better one, I&#39;ll update this article.&lt;/p&gt;
&lt;p&gt;I hope that helps!&lt;/p&gt;
</description>
      <pubDate>Tue, 30 Jul 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/arguments-or-parameters/</guid>
    </item>
    <item>
      <title>Add event listener for class change</title>
      <link>https://seanmcp.com/articles/event-listener-for-class-change/</link>
      <description>&lt;p&gt;🆕 &lt;strong&gt;Update:&lt;/strong&gt; I created a
&lt;a href=&quot;https://seanmcp.com/articles/listen-for-class-change-in-javascript&quot;&gt;reusable function to listen for class changes on any element&lt;/a&gt;
that is more robust that the solution here.&lt;/p&gt;
&lt;p&gt;If you&#39;re like me and spent some time searching for an event listener for class
changes, let me save you some time: &lt;strong&gt;there isn&#39;t one&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;However, you can create your own custom event listener using the
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver&quot;&gt;&lt;code&gt;MutationObserver&lt;/code&gt; API&lt;/a&gt;.
Let&#39;s look at how to create a simple listener for class changes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MutationObserver&lt;/code&gt; is a constructor that can allows you to watch any changes to
the DOM tree. The constructor takes a callback function that will receive two
arguments: a list of
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord&quot;&gt;MutationRecords&lt;/a&gt;,
and a reference to the observer.&lt;/p&gt;
&lt;p&gt;First, let&#39;s first create a callback that logs its parameters and then construct
a new &lt;code&gt;MutationObserver&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mutationsList&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; observer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Mutations:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mutationsList&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Observer:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; observer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mutationObserver &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MutationObserver&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;callback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;ve constructed basic custom observer, but we need to listen for changes on
something. To add our custom event listener, we need to call the created
observer&#39;s
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe&quot;&gt;&lt;code&gt;observe()&lt;/code&gt; method&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MutationObserver.observe()&lt;/code&gt; takes two arguments: the DOM node target, and an
optional options object. We&#39;ll call this method and pass it a node reference and
one option:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;mutationObserver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This set our &lt;code&gt;MutationObserver&lt;/code&gt; to look for any changes to the &lt;code&gt;main&lt;/code&gt;&#39;s
attributes. If we trigger a change, we can see the two logs from &lt;code&gt;callback()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Mutations:
[MutationRecord]

Observer:
MutationObserver
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On each &lt;code&gt;MutationRecord&lt;/code&gt; object, there is an &lt;code&gt;attributeName&lt;/code&gt; property. If that
value is equal to &#39;class&#39;, then we know that there has been a change to the
element&#39;s class name.&lt;/p&gt;
&lt;p&gt;Now we can update the &lt;code&gt;callback&lt;/code&gt; function by adding a condition:&lt;/p&gt;
&lt;!-- ```js/0-5 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mutationsList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  mutationsList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mutation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mutation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;attributeName &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;class&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Ch-ch-ch-changes!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will fire an alert if any item in &lt;code&gt;mutationsList&lt;/code&gt; records a change to
&lt;code&gt;main&lt;/code&gt;&#39;s class attribute.&lt;/p&gt;
&lt;p&gt;If you need to stop your custom event listener later, use &lt;code&gt;MutationObserver&lt;/code&gt;&#39;s
&lt;code&gt;disconnect()&lt;/code&gt; method to remove it like you would a normal event listener:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;mutationObserver&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;disconnect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;example&quot; tabindex=&quot;-1&quot;&gt;Example&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/event-listener-for-class-change/#example&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Example”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Checkout a working example of custom event listener for class change on CodePen:&lt;/p&gt;
&lt;iframe height=&quot;500&quot; style=&quot;width: 100%;&quot; scrolling=&quot;no&quot; title=&quot;Event listener for class change&quot; src=&quot;https://codepen.io/SeanMcP/embed/preview/RmWJvV/?height=500&amp;theme-id=0&amp;default-tab=js,result&quot; frameborder=&quot;no&quot; allowtransparency=&quot;true&quot; allowfullscreen=&quot;true&quot;&gt;
  See the Pen &lt;a href=&quot;https://codepen.io/SeanMcP/pen/RmWJvV/&quot;&gt;Event listener for class change&lt;/a&gt; by Sean McPherson
  (&lt;a href=&quot;https://codepen.io/SeanMcP&quot;&gt;@SeanMcP&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.
&lt;/iframe&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Fri, 10 May 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/event-listener-for-class-change/</guid>
    </item>
    <item>
      <title>Storing data in state vs. class variable</title>
      <link>https://seanmcp.com/articles/storing-data-in-state-vs-class-variable/</link>
      <description>&lt;p&gt;This past week I was working with a new coworker who has previous experience
developing but is new to React. After picking up a few syntax cues, he started
writing class components in what was a familiar manner for him: storing
information as class variables in the constructor.&lt;/p&gt;
&lt;p&gt;The constructor from one of his components looked like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;default&#39;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Later on, when he wanted to update the value stored on the object, he did with a
simple reassignment:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;new value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After reviewing his code, I tried to explain the &amp;quot;correct&amp;quot; pattern for storing
data in React. I said (something like):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I see that you&#39;re using class variables to store information on your React
component. That&#39;s not a common pattern. Instead, we use a state object that is
referenced with &lt;code&gt;this.state.whatever&lt;/code&gt;. When we want to update the data, we
call &lt;code&gt;this.setState&lt;/code&gt; and pass the new information.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He naturally asked why that was the case, because his code was working as is. I
went into a mealy-mouthed explanation with gem quotes like &amp;quot;classes in React
aren&#39;t &lt;em&gt;true&lt;/em&gt; classes&amp;quot;, and &amp;quot;state isn&#39;t &lt;em&gt;actually&lt;/em&gt; stored in the component&amp;quot;.
None of what I stumbled through answered his original question.&lt;/p&gt;
&lt;p&gt;Realizing that I was talking out of ignorance, I stopped and offered a more
honest: &amp;quot;Actually, I don&#39;t really know.&amp;quot; Then I turned to Google to find the
answer.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;class-variables&quot; tabindex=&quot;-1&quot;&gt;Class variables&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/storing-data-in-state-vs-class-variable/#class-variables&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Class variables”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I thought that storing class variables was almost always a bad idea. The only
use cases that I had personally encountered before were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setting and clearing timeouts&lt;/li&gt;
&lt;li&gt;Storing frequently-referenced values&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, my colleague&#39;s work showed that class variables can be used to manage
and update data.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of using class variables to create a counter:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VariableCounter&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;The count is&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;increment&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Add one&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the component is initiated, a class variable named &lt;code&gt;count&lt;/code&gt; is set to &lt;code&gt;0&lt;/code&gt;.
When the &lt;code&gt;increment&lt;/code&gt; method is called, it updates &lt;code&gt;count&lt;/code&gt; by adding one to the
previous value. The rest of the component is pretty standard.&lt;/p&gt;
&lt;p&gt;After writing up this simple example, I thought this code would work. But I was
wrong. You can click the button as much as you want, but the &lt;code&gt;count&lt;/code&gt; value
displayed in the component will never change.&lt;/p&gt;
&lt;p&gt;If you throw a breakpoint or add a &lt;code&gt;console.log&lt;/code&gt; to &lt;code&gt;increment()&lt;/code&gt;, you&#39;d see
that the method is indeed called and the value of &lt;code&gt;this.count&lt;/code&gt; is incremented,
but the component never reflects the change.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That&#39;s because React components will only re-render when there are changes to
&lt;code&gt;props&lt;/code&gt; or &lt;code&gt;state&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Updating the class variable involves neither, so it does not trigger a
re-render. This explains why the &lt;code&gt;count&lt;/code&gt; changes in our example, but the
displayed value never updates.&lt;/p&gt;
&lt;p&gt;In order to use class variables, we need to take the responsibility of
triggering the re-render when our data changes. To do that, we need to add a
line to our example:&lt;/p&gt;
&lt;!-- ```js/14 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VariableCounter&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;The count is&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;increment&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Add one&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forceUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;React class components have a &lt;code&gt;forceUpdate&lt;/code&gt; method that triggers the &lt;code&gt;render&lt;/code&gt;
method. By calling &lt;code&gt;this.forceUpdate()&lt;/code&gt; after incrementing our class value, we
can get our displayed value to update.&lt;/p&gt;
&lt;p&gt;I had never heard of this method before, and there is a reason why: the React
team doesn&#39;t recommend using it. Here&#39;s a line from
&lt;a href=&quot;https://reactjs.org/docs/react-component.html#forceupdate&quot;&gt;the React documentation on &lt;code&gt;forceUpdate&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Normally you should try to avoid all uses of &lt;code&gt;forceUpdate()&lt;/code&gt; and only read
from &lt;code&gt;this.props&lt;/code&gt; and &lt;code&gt;this.state&lt;/code&gt; in &lt;code&gt;render()&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In some instances you may receive data from other sources, but otherwise &lt;strong&gt;try
to avoid manually managing a component&#39;s render&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The alternative to using class variables and forcing updates is leveraging
React&#39;s component state.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;component-state&quot; tabindex=&quot;-1&quot;&gt;Component State&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/storing-data-in-state-vs-class-variable/#component-state&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Component State”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Instead of setting our count as a class variable, let&#39;s instead create a state
object on our class and store the data there.&lt;/p&gt;
&lt;p&gt;We only need to make a few modifications to the &lt;code&gt;VariableCounter&lt;/code&gt; for our new
component:&lt;/p&gt;
&lt;!-- ```js/1-3,8,15-17 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StateCounter&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;The count is&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;increment&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Add one&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;increment&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token parameter&quot;&gt;prevState&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; prevState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While instantiating a state object might look like the previous example using a
class variable, &lt;code&gt;state&lt;/code&gt; is a protected keyword in React that refers to stored
component data.&lt;/p&gt;
&lt;p&gt;You can access data from state with normal object dot or bracket notation, so
the current count can be referenced with &lt;code&gt;this.state.count&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The major difference between using class variables and state is updating data.
Instead of manually reassigning the variable, you call &lt;code&gt;this.setState()&lt;/code&gt; and
pass it an object or a function that returns an object.&lt;/p&gt;
&lt;p&gt;When you call &lt;code&gt;this.setState()&lt;/code&gt;, React merges the passed object into the current
state to create a new state object. Then it compares this new state to the
previous state. If there is a change, React re-renders the component, resulting
in the updated &lt;code&gt;count&lt;/code&gt; value displayed on the screen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By using &lt;code&gt;this.setState()&lt;/code&gt;, you let React handle the logic of whether to
re-render the component.&lt;/strong&gt; This is a feature of React and one of the reasons it
has become so popular.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;example&quot; tabindex=&quot;-1&quot;&gt;Example&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/storing-data-in-state-vs-class-variable/#example&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Example”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I created a CodeSandbox example of the components discussed above. There are
working state and class variable counters; with a bonus functional component
using &lt;code&gt;React.useState()&lt;/code&gt;, and a broken class variable counter without
&lt;code&gt;this.forceUpdate()&lt;/code&gt;. Check it out:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/n40x05xy8l?fontsize=14&quot; title=&quot;React State vs. Class Variables&quot; style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot; sandbox=&quot;allow-modals allow-forms allow-popups allow-scripts allow-same-origin&quot;&gt;&lt;/iframe&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/storing-data-in-state-vs-class-variable/#summary&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Summary”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Contrary to what I initially thought, it&#39;s okay to store component data as a
class variable. However, if you&#39;re going to render that data, you should instead
store it in state so that any changes trigger a re-render. &lt;strong&gt;Ninety-five percent
of the time, you&#39;ll store data in state.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now that you know the difference between storing data in state and class
variables, you can be more helpful than I was to your fellow developers.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Fri, 12 Apr 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/storing-data-in-state-vs-class-variable/</guid>
    </item>
    <item>
      <title>Filter out premium Medium articles</title>
      <link>https://seanmcp.com/articles/filter-premium-medium-articles/</link>
      <description>&lt;p&gt;Medium has received a lot of flack recently for their push to monetize the
platform. And while I don&#39;t fault them for moving some of their best articles
behind a pay wall, I have no interest in subscribing to their platform.&lt;/p&gt;
&lt;p&gt;There is still a lot of high-quality free content on Medium, but you have to
navigate around all of the premium content that the platform is pushing.&lt;/p&gt;
&lt;p&gt;I wanted to write a console script that would do that filtering work for me.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;reach-for-the-stars&quot; tabindex=&quot;-1&quot;&gt;Reach for the stars&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/filter-premium-medium-articles/#reach-for-the-stars&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Reach for the stars”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;On Medium, premium articles can be identified on the homepage by their ★ icon.
Using the inspector, you can see that the star is an &lt;code&gt;svg&lt;/code&gt; element nested in a
&lt;code&gt;span&lt;/code&gt; with the class &lt;code&gt;svgIcon--star&lt;/code&gt;. Bingo!&lt;/p&gt;
&lt;p&gt;Now, using the handy &lt;code&gt;querySelectorAll&lt;/code&gt;-esque selector &lt;code&gt;$$&lt;/code&gt;, we can find all the
stars on the page. Our console script starts out like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;span.svgIcon--star&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we&#39;ve selected all stars, we need to iterate over them. Since we need
to do something for every item in our iterable, we&#39;ll use &lt;code&gt;forEach&lt;/code&gt;:&lt;/p&gt;
&lt;!-- ```js/0,2 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;span.svgIcon--star&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;star&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Hide parent element&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we&#39;re iterating over the stars, we need to find and hide the
appropriate parent element. To do this, we&#39;ll use a neat &lt;code&gt;Element&lt;/code&gt; method called
&lt;code&gt;closest&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;finding-a-parent-with-closest&quot; tabindex=&quot;-1&quot;&gt;Finding a parent with &lt;code&gt;closest&lt;/code&gt;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/filter-premium-medium-articles/#finding-a-parent-with-closest&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Finding a parent with closest”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;You may be familiar with the &lt;code&gt;querySelector&lt;/code&gt; method, which starts with a given
element and then searches down the DOM tree and returns the first match.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;closest&lt;/code&gt; works the same way, but in reverse. It starts with an element, then
travels &lt;strong&gt;up&lt;/strong&gt; the DOM tree. This makes it the perfect method for starting with
an element and looking for a specific parent.&lt;/p&gt;
&lt;p&gt;Using the inspector again, we can see that articles outside the featured section
are &lt;code&gt;div&lt;/code&gt;s with the class &lt;code&gt;streamItem&lt;/code&gt;. Using &lt;code&gt;closest&lt;/code&gt;, we&#39;ll grab those
elements:&lt;/p&gt;
&lt;!-- ```js/1 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;span.svgIcon--star&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;star&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  star&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.streamItem&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Hide element&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had never used the &lt;code&gt;closest&lt;/code&gt; method before and was glad to find it. As always,
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/closest&quot;&gt;I read up about it on MDN&lt;/a&gt;
before using it.&lt;/p&gt;
&lt;p&gt;We&#39;ve selected the correct parent element; now we need to hide it.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;hiding-an-element&quot; tabindex=&quot;-1&quot;&gt;Hiding an element&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/filter-premium-medium-articles/#hiding-an-element&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Hiding an element”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Removing an element in JavaScript is more difficult than it should be. There is
no &lt;code&gt;remove&lt;/code&gt; method on the global &lt;code&gt;Element&lt;/code&gt;. Instead, you need to jump up to the
parent element and then use &lt;code&gt;removeChild&lt;/code&gt;. The normal strategy looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; element &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.remove-me&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

element&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parentElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;element&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think this pattern is annoying and try to avoid it whenever possible. But we
could use it in our instance by first creating a variable to reference the
element to be removed:&lt;/p&gt;
&lt;!-- ```js/2,3 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Option 1 - Remove element&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;span.svgIcon--star&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;star&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; article &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; star&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.streamItem&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  article&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parentElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;article&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is your best option if you need to remove the element from the DOM.&lt;/p&gt;
&lt;p&gt;My preferred method leaves the element in the DOM and applies CSS styles to hide
it from view. We&#39;ll set the article element&#39;s &lt;code&gt;display&lt;/code&gt; style to &lt;code&gt;&#39;none&#39;&lt;/code&gt;:&lt;/p&gt;
&lt;!-- ```js/2 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Option 2 - Hide element&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;$$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;span.svgIcon--star&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;star&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  star&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.streamItem&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;display &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unless you &lt;strong&gt;need&lt;/strong&gt; to remove and element from the DOM, the simpler solution is
to just hide the element.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;save-for-later&quot; tabindex=&quot;-1&quot;&gt;Save for later&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/filter-premium-medium-articles/#save-for-later&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Save for later”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Chrome has a handy feature in the &amp;quot;Sources&amp;quot; tab called snippets. Here you can
save bits of code for use later.&lt;/p&gt;
&lt;p&gt;I created a snippet title &amp;quot;Medium&amp;quot; and saved the above code. Now when I want to
filter out premium articles, I just need to run that snippet with
&lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;enter&lt;/kbd&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;read-on&quot; tabindex=&quot;-1&quot;&gt;Read on&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/filter-premium-medium-articles/#read-on&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Read on”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Now the next time I want to find an article to read on Medium, I can run the
snippet and filter out premium articles.&lt;/p&gt;
&lt;p&gt;For a more reusable solution, we could turn this snippet into a browser
extension, but that&#39;s the topic of another article.&lt;/p&gt;
</description>
      <pubDate>Mon, 08 Apr 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/filter-premium-medium-articles/</guid>
    </item>
    <item>
      <title>Adding accessibility checks to your React app</title>
      <link>https://seanmcp.com/articles/adding-accessibility-checks-to-react/</link>
      <description>&lt;p&gt;&lt;strong&gt;Updated - 3/9/19&lt;/strong&gt; This article was initially released with a reference to a
third tool for React accessibility checking: &lt;code&gt;react-a11y&lt;/code&gt;. Since publication,
that library has been deprecated. The article has been updated to reflect that
change.&lt;/p&gt;
&lt;p&gt;Whether you are working for a startup, non-profit, or Fortune 500 company,
accessibility is a critical component of your product. Not only it is a legal
requirement in many countries&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/adding-accessibility-checks-to-react/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, but creating accessible applications
maximizes the number of potential users. And it often has a positive impact on
all users
(&lt;a href=&quot;https://ssir.org/articles/entry/the_curb_cut_effect&quot;&gt;read about the &amp;quot;Curb Cut Effect&amp;quot;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;As React developers, we have a responsibility to avoid hiding in the virtual DOM
and work to ensure that the components we craft are going to work for everyone.
Fortunately for us, React has
&lt;a href=&quot;https://reactjs.org/docs/accessibility.html&quot;&gt;React has accessibility features built into the platform&lt;/a&gt;
to make our jobs easier.&lt;/p&gt;
&lt;p&gt;In this article, we&#39;re going to look at two additional tools than can help React
developers create awesome and accessible applications for all.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;setup&quot; tabindex=&quot;-1&quot;&gt;Setup&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/adding-accessibility-checks-to-react/#setup&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Setup”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;To demonstrate these features, I&#39;m going to bootstrap a new project with React&#39;s
&lt;a href=&quot;https://facebook.github.io/create-react-app/&quot;&gt;Create React App&lt;/a&gt;. It&#39;s a great
way to spin up a new project and works nicely with the accessibility checks
we&#39;re going to implement.&lt;/p&gt;
&lt;p&gt;If you&#39;re looking to add these checks to a current project, the only dependency
is ESLint, which we&#39;ll look at later in this article. Now, let&#39;s jump in!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;react-axe&quot; tabindex=&quot;-1&quot;&gt;React-axe&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/adding-accessibility-checks-to-react/#react-axe&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “React-axe”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Create React App already has wonderfully helpful console messages, and react-axe
is an out-of-the-box solution that adds accessibility checking to your console.&lt;/p&gt;
&lt;p&gt;React-axe is developed by Deque, the makers of the fantastic accessibility tools
like the &lt;a href=&quot;https://www.deque.com/axe/&quot;&gt;Axe browser extension&lt;/a&gt; (which I highly
recommend). Install it in the usual way:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn add --dev react-axe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once installed, we&#39;ll check for a development environment before requiring and
calling react-axe&#39;s &lt;code&gt;axe&lt;/code&gt; function and passing certain parameters.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ReactDOM &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react-dom&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; App &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./components/App&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;evn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;development&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; axe &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;react-axe&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;axe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;App &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final parameter for &lt;code&gt;axe&lt;/code&gt; is &amp;quot;a timing delay in milliseconds that will be
observed between each component change and the time the analysis starts&amp;quot;
(&lt;a href=&quot;https://github.com/dequelabs/react-axe/#initialize-the-module&quot;&gt;source&lt;/a&gt;). We&#39;ll
set it to 1000ms, or one second.&lt;/p&gt;
&lt;p&gt;Now if I give an element an invalid role (&lt;em&gt;e.g.&lt;/em&gt; &lt;code&gt;role=&amp;quot;Test&amp;quot;&lt;/code&gt;), I&#39;m met with
the following console message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;▸ critical: ARIA roles used must conform to valid values
https://dequeuniversity.com/rules/axe/3.1/aria-roles?application=axeAPI
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Expanding the message provides a reference to the original document, and a file
and line reference to fix the issue. The console errors are helpful without
being overwhelming and provide all the information and resources you need to fix
the issue.&lt;/p&gt;
&lt;p&gt;Console warnings are great, but let&#39;s add another tool to help catch mistakes
before they make it to the browser.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;jsx-a11y&quot; tabindex=&quot;-1&quot;&gt;Jsx-a11y&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/adding-accessibility-checks-to-react/#jsx-a11y&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Jsx-a11y”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Jsx-a11y is an ESLint plugin that looks over your code for some key
accessibility considerations. If you don&#39;t have ESLint added to your project
yet, follow their
&lt;a href=&quot;https://eslint.org/docs/user-guide/getting-started&quot;&gt;get started guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you bootstrapped your React app with &lt;code&gt;create-react-app&lt;/code&gt; like I did, it
already has ESLint and some of jsx-a11y&#39;s accessibility checking included. For
the sake of this article, we&#39;re going to add the full set of rules, so we&#39;ll
need to install the plugin library:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn add --dev eslint-plugin-jsx-a11y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then modify the ESLint configs in your &lt;code&gt;package.json&lt;/code&gt; to match the following:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;eslintConfig&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;plugins&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;jsx-a11y&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;extends&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;react-app&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plugin:jsx-a11y/recommended&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if we make a change that reduces our app&#39;s accessibility, like removing the
&lt;code&gt;alt&lt;/code&gt; attribute for an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, we&#39;re met with the following lint warning:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./src/components/App/App.js
    Line 10:  img elements must have an alt prop, either with meaningful text, or an empty string for decorative images  jsx-a11y/alt-text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For more customization over which rules jsx-a11y uses, refer to
&lt;a href=&quot;https://github.com/evcohen/eslint-plugin-jsx-a11y#eslint-plugin-jsx-a11y&quot;&gt;the official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you are using a text editor like VS Code that features in-line linting, you
can identify and fix potential accessibility issues before you even save.&lt;/p&gt;
&lt;p&gt;With these tools in place, you&#39;re well on your way to creating more accessible
React applications!&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;a11y-react-starter&quot; tabindex=&quot;-1&quot;&gt;A11y-react-starter&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/adding-accessibility-checks-to-react/#a11y-react-starter&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “A11y-react-starter”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I created &lt;a href=&quot;https://github.com/seanmcp/a11y-react-starter&quot;&gt;&lt;code&gt;a11y-react-starter&lt;/code&gt;&lt;/a&gt;,
a lightly-configured create-react-app with both of the above accessibility tools
baked in. Check it out for a reference or use it as a starting point for your
next app.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/adding-accessibility-checks-to-react/#conclusion&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Conclusion”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;By enabling these accessibility features, you&#39;re adding the wisdom and knowledge
of the many developers who have gone before you. With their help, and a little
bit of learning, anyone can create accessible applications that work for all
users.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Web_accessibility#Web_accessibility_legislation&quot;&gt;Web accessibility: Web accessibility legislation&lt;/a&gt;
on Wikipedia &lt;a href=&quot;https://seanmcp.com/articles/adding-accessibility-checks-to-react/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 04 Mar 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/adding-accessibility-checks-to-react/</guid>
    </item>
    <item>
      <title>Three reasons to learn Python</title>
      <link>https://seanmcp.com/articles/three-reasons-to-learn-python/</link>
      <description>&lt;p&gt;There are tons of reasons to learn a programming language. Maybe you are new to
coding and are looking for a good place to start. Maybe you’re interested in new
technologies like machine learning and artificial intelligence and want to learn
more. Or maybe you’re a seasoned developer who is looking to add a new language
to his/her skill set.&lt;/p&gt;
&lt;p&gt;But which to choose? There are
&lt;a href=&quot;https://www.quora.com/How-many-programming-languages-are-there-in-the-world&quot;&gt;hundreds of programming languages out there&lt;/a&gt;,
each one vying for your attention. What should you do?&lt;/p&gt;
&lt;p&gt;Never fear, faithful reader! Here are three reasons why you (yes, you!) should
learn the &lt;strong&gt;Python&lt;/strong&gt; programming language.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;1---versatile&quot; tabindex=&quot;-1&quot;&gt;1-- Versatile&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/three-reasons-to-learn-python/#1---versatile&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “1-- Versatile”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Python’s creator, Guido van Rossum, designed Python to be a general purpose
programming language. As a result, Python can be used in a wide variety of
cases: machine learning, web development, GUI development, scientific and
numeric applications, software development, system administration, and more.
Whatever type of programming sparks your interest, there is probably
&lt;a href=&quot;https://www.python.org/about/apps/&quot;&gt;a Python application or framework for it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Major companies like Google, Instagram, Dropbox, Spotify, Reddit, Duolingo, and
BitBucket; government organizations; educational institutions; and non-profits
use Python for its versatility.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;2---beginner-friendly&quot; tabindex=&quot;-1&quot;&gt;2-- Beginner friendly&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/three-reasons-to-learn-python/#2---beginner-friendly&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “2-- Beginner friendly”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In addition to being a general purpose programming language, Python advertises
itself as being
“&lt;a href=&quot;https://docs.python.org/3.6/tutorial/appetite.html&quot;&gt;easy to use&lt;/a&gt;”. It achieves
this by utilizing a simple and intuitive syntax and offering high-level data
types like dictionaries.&lt;/p&gt;
&lt;p&gt;Since 1999, Python has been guided by a series of 19 principles called the “Zen
of Python.” Among these are specific guidelines to keep things simple:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Simple is better than complex.
Readability counts.
If the implementation is hard to explain, it&#39;s a bad idea.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a result of this, Python is often used as the language in introductory
computer science courses (notably
&lt;a href=&quot;https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016/index.htm&quot;&gt;MIT&lt;/a&gt;).
If you are looking to learn your first language or add to a growing toolbelt,
Python is a great choice.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;3---highly-rated&quot; tabindex=&quot;-1&quot;&gt;3-- Highly rated&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/three-reasons-to-learn-python/#3---highly-rated&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “3-- Highly rated”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In my experience, every Python developer I have met loves working in Python. And
it turns out that my anecdotal observation may be right!&lt;/p&gt;
&lt;p&gt;In
&lt;a href=&quot;https://insights.stackoverflow.com/survey/2018/&quot;&gt;StackOverlow’s Developer Survey&lt;/a&gt;-- which
compiles user responses to demographic, technology, and work questions--shows
that Python is a desirable language. It has been listed among the
“&lt;a href=&quot;https://insights.stackoverflow.com/survey/2018/##most-loved-dreaded-and-wanted&quot;&gt;Most Loved&lt;/a&gt;”
languages for a while and has topped the charts in the past two years as the
“&lt;a href=&quot;https://insights.stackoverflow.com/survey/2018/&quot;&gt;Most Desired&lt;/a&gt;” language. If a
lot of other developers like using Python, or want to learn Python, then it is
probably going to be a good experience.&lt;/p&gt;
&lt;p&gt;[Sidebar: If you haven’t before, take the time to look over the results of the
&lt;a href=&quot;https://insights.stackoverflow.com/survey/2018/&quot;&gt;2018 Developer Survey&lt;/a&gt;. It
isn’t perfect, suffering from both
&lt;a href=&quot;https://en.wikipedia.org/wiki/Participation_bias&quot;&gt;participation&lt;/a&gt; and
&lt;a href=&quot;https://en.wikipedia.org/wiki/Response_bias&quot;&gt;response bias&lt;/a&gt;, but does open a
window into the world of development.]&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;bonus---python-jokes!&quot; tabindex=&quot;-1&quot;&gt;Bonus-- Python jokes!&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/three-reasons-to-learn-python/#bonus---python-jokes!&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Bonus-- Python jokes!”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Van Rossum named the Python programming language not after the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Python_%28genus%29&quot;&gt;serpent genus&lt;/a&gt; (as I
previously assumed) but after the British TV comedy “Monty Python’s Flying
Circus.” According to the
&lt;a href=&quot;https://docs.python.org/3.6/tutorial/appetite.html&quot;&gt;Python Software Foundation&lt;/a&gt;,
“Making references to Monty Python skits in documentation is not only allowed,
it is encouraged!”&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.giphy.com/media/RBEUIVI6ey5Ta/giphy.webp&quot; alt=&quot;The laughing French knight from Monty Python&#39;s Holy Grail&quot;&gt;&lt;/p&gt;
&lt;p&gt;There you go: three (and a half) reasons why you should learn Python.&lt;/p&gt;
&lt;p&gt;If you are looking for a good place to get started, I recommend the
&lt;a href=&quot;https://docs.python.org/3/&quot;&gt;Python Docs&lt;/a&gt;: they are well-written and -paced for
a beginner diving into the language.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Thu, 21 Feb 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/three-reasons-to-learn-python/</guid>
    </item>
    <item>
      <title>JS Basics: Generate a random number</title>
      <link>https://seanmcp.com/articles/js-generate-random-number/</link>
      <description>&lt;p&gt;Whether you are simulating a die roll or pulling any index from an array,
computers can be used to generate a random number. In JavaScript, random numbers
require a combination of methods on the &lt;code&gt;Math&lt;/code&gt; object that can be a little
tricky to understand your first time through.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;random-die-roll&quot; tabindex=&quot;-1&quot;&gt;Random die roll&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/js-generate-random-number/#random-die-roll&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Random die roll”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Let’s say you want to create a digital six-sided die, which will give you a
random number between one and six when called. Our function to simulate a die
roll will look like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;rollDie&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;sides&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; sides&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;rollDie&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every time we call the function, it will return any number from one to six,
inclusive. But why? To answer that question, we need to know more about the two
methods on the &lt;code&gt;Math&lt;/code&gt; object we called.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;math-methods&quot; tabindex=&quot;-1&quot;&gt;Math methods&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/js-generate-random-number/#math-methods&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Math methods”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Math.random()&lt;/code&gt; is a method that generates an integer (number with a decimal)
from zero to one, including zero but excluding one. The output of
&lt;code&gt;Math.random()&lt;/code&gt; could be 0, 0.1, 0.2, 0.3343424587866554652345, or 0.99.
Anything from zero to nearly one is a possibility.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Math.floor&lt;/code&gt; is a method that rounds an integer down to the nearest whole
number. Rounding down, 0.1 becomes 0, 3.6 becomes 3, and 5.4 becomes 5. Think of
it as rounding all the way down to the floor. (Note: there is also a &lt;code&gt;Math.ceil&lt;/code&gt;
function for rounding up that I&#39;ll mention later).&lt;/p&gt;
&lt;p&gt;By combining these two methods, we can generate the random number for our die.
Starting on the inside of our function and working outward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Math.random()&lt;/code&gt; returns an integer &lt;strong&gt;between&lt;/strong&gt; zero and nearly one: &lt;code&gt;0.16&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Next we &lt;strong&gt;multiply&lt;/strong&gt; that integer by the number of sides: &lt;code&gt;0.16 * 6 = 0.96&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Then we &lt;strong&gt;round&lt;/strong&gt; that product up with &lt;code&gt;Math.floor&lt;/code&gt;: &lt;code&gt;0.96 -&amp;gt; 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Finally, we &lt;strong&gt;add&lt;/strong&gt; one to get our final random number: &lt;code&gt;0 + 1 = 1&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The result of our &lt;code&gt;rollDie(6)&lt;/code&gt; function is &lt;code&gt;1&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;Our function allows for a varying number of sides, so you would only need to
pass a different argument if you were rolling a different die (much to the
satisfaction of all
&lt;a href=&quot;https://en.wikipedia.org/wiki/Dungeons_%26_Dragons#Game_mechanics&quot;&gt;D&amp;amp;D players&lt;/a&gt;
out there).&lt;/p&gt;
&lt;p&gt;You might even create some help functions to simplify calling different sided
dice:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;rollD6&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rollDie&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;rollD12&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rollDie&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;rollD20&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rollDie&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// etc...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I used functions like these in Dice Roller, a handy dice rolling app for
table-top gaming. You can
&lt;a href=&quot;https://github.com/SeanMcP/dice-roller&quot;&gt;view the project&#39;s source code here&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;common-questions&quot; tabindex=&quot;-1&quot;&gt;Common questions&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/js-generate-random-number/#common-questions&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Common questions”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Here are some questions you may have (I know I did!) about our &lt;code&gt;rollDie&lt;/code&gt;
function:&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;%E2%80%9Cwhy-did-we-need-to-add-one-to-our-number%3F%E2%80%9D&quot; tabindex=&quot;-1&quot;&gt;“Why did we need to add one to our number?”&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/js-generate-random-number/#%E2%80%9Cwhy-did-we-need-to-add-one-to-our-number%3F%E2%80%9D&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to ““Why did we need to add one to our number?””&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Math.floor(Math.random() * 6)&lt;/code&gt; alone will generate a random number between 0
and 5. That is six options, but I&#39;ve never seen a die numbered from zero to
five. We add one to the output so that it makes sense for our situation.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;%22wouldn&#39;t-using-math.ceil-make-the-%2B-1-unnecessary%3F%22&quot; tabindex=&quot;-1&quot;&gt;&amp;quot;Wouldn&#39;t using &lt;code&gt;Math.ceil&lt;/code&gt; make the &lt;code&gt;+ 1&lt;/code&gt; unnecessary?&amp;quot;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/js-generate-random-number/#%22wouldn&#39;t-using-math.ceil-make-the-%2B-1-unnecessary%3F%22&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “&amp;quot;Wouldn&#39;t using Math.ceil make the + 1 unnecessary?&amp;quot;”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In the same manner that &lt;code&gt;Math.floor&lt;/code&gt; rounded our integer down to the nearest
whole number, &lt;code&gt;Math.ceil&lt;/code&gt;--short for &amp;quot;ceiling&amp;quot;--rounds an integer up. At face
value, this would simplify our solution--but for one issue:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since &lt;code&gt;Math.random()&lt;/code&gt; &lt;strong&gt;can&lt;/strong&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/js-generate-random-number/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; return a &lt;code&gt;0&lt;/code&gt;, using &lt;code&gt;Math.ceil&lt;/code&gt; would on a
rare instance return an unexpected value. So it&#39;s safer to use &lt;code&gt;Math.floor&lt;/code&gt; and
add one.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;%22does-the-math-always-work-out%3F%22&quot; tabindex=&quot;-1&quot;&gt;&amp;quot;Does the math always work out?&amp;quot;&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/js-generate-random-number/#%22does-the-math-always-work-out%3F%22&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “&amp;quot;Does the math always work out?&amp;quot;”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I’ve included a few additional examples at the bottom of this post&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/js-generate-random-number/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;. Try it
out for yourself and see!
&lt;span role=&quot;img&quot; aria-label=&quot;smiling face with squinting eyes emoji&quot;&gt;😊&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;random-item-from-an-array&quot; tabindex=&quot;-1&quot;&gt;Random item from an array&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/js-generate-random-number/#random-item-from-an-array&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Random item from an array”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;rollDie&lt;/code&gt; works well for our dice example, but what if you want to select a
random item from an array? Remember, that
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Accessing_array_elements&quot;&gt;arrays are zero-indexed (MDN)&lt;/a&gt;,
which means that the first item of an array is accessed with a zero (&lt;code&gt;0&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; myArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;first&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;second&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;third&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

myArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &#39;first&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our &lt;code&gt;rollDie&lt;/code&gt; function will never return a &lt;code&gt;0&lt;/code&gt; because we&#39;re always adding one.
By removing that addition, we can create a new function that will work well with
arrays. Let&#39;s use the code from the previous block and add:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;randomIndex&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arrayLength&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; arrayLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;randomIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By calling our function and passing the length of our array, we can pull a
random item from our array:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;myArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;randomIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &#39;second&#39;&lt;/span&gt;
myArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;randomIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &#39;first&#39;&lt;/span&gt;
myArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;randomIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &#39;second&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using our function in this manner is a little repetitive, so let&#39;s create
another function that will simplify the process for us:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;randomItemFrom&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;randomIndex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;randomItemFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &#39;third&#39;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;randomItemFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &#39;second&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we have a few handy utility functions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;rollDie&lt;/code&gt; for simulating a die roll with a given number of sides,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;randomIndex&lt;/code&gt; for getting a valid index from an array, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;randomItemFrom&lt;/code&gt; for returning a random item from an array&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While building those, we learned about JavaScript&#39;s &lt;code&gt;Math&lt;/code&gt; object and some of
its methods: &lt;code&gt;random&lt;/code&gt;, &lt;code&gt;floor&lt;/code&gt;, and &lt;code&gt;ceil&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I emphasize &amp;quot;can&amp;quot; because it is an
&lt;a href=&quot;https://en.wikipedia.org/wiki/Edge_case&quot;&gt;edge case (Wikipedia)&lt;/a&gt;: a
statistically unlikely but possible event. Programmers need to be on the
lookout and account for edge cases when possible. &lt;a href=&quot;https://seanmcp.com/articles/js-generate-random-number/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Additional examples stepping through the &lt;code&gt;rollDie&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. Math.random()    // 0.4
2. Multiply by 6    // 2.4
3. Math.floor       // 2
4. Add one          // 3
Random number: 3

1. Math.random()    // 0.9
2. Multiply by 6    // 5.4
3. Math.floor       // 5
4. Add one          // 6
Random number: 6

1. Math.random()    // 0.642
2. Multiply by 6    // 3.8520000000000003
3. Math.floor       // 3
4. Add one          // 4
Random number: 4
&lt;/code&gt;&lt;/pre&gt;
 &lt;a href=&quot;https://seanmcp.com/articles/js-generate-random-number/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Mon, 11 Feb 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/js-generate-random-number/</guid>
    </item>
    <item>
      <title>JS Basics: Ternary Operator</title>
      <link>https://seanmcp.com/articles/js-ternary-operator/</link>
      <description>&lt;p&gt;A ternary or conditional operator is like an inline if statement. In JavaScript,
you can identify them by their unique use of a question mark, &lt;code&gt;?&lt;/code&gt;, and colon,
&lt;code&gt;:&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When I first started coding, I found ternary operators more than a little
confusing, so let&#39;s try to unpack them. Look at this common example:&lt;/p&gt;
&lt;!-- ```js/1 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Todo &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isDone &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Todo--done&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we have a snippet from a React to-do app with a ternary operator. The class
( &lt;code&gt;className&lt;/code&gt; in JSX) is being set based on a condition in our &lt;code&gt;props&lt;/code&gt; object.
Here’s how to read a ternary operator:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If &lt;code&gt;props.isDone&lt;/code&gt; is true/truthy, then return the string &amp;quot;Todo--done&amp;quot;;
otherwise return an empty string.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Written out, a ternary operator looks like an &lt;code&gt;if&lt;/code&gt; statement. We could express
the same code like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isDone &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Todo--done&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That looks more familiar! Ternary operators are useful because they allow you to
add inline conditions to your code. Compare the original code to our final if
statement. The ternary operator is shorter, cleaner, and more efficient.&lt;/p&gt;
&lt;p&gt;MDN has a great list of other examples for you to reference. You can check them
out here:
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator&quot;&gt;Conditional (ternary) operators&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</description>
      <pubDate>Fri, 08 Feb 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/js-ternary-operator/</guid>
    </item>
    <item>
      <title>Convert class components to functions with React Hooks</title>
      <link>https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/</link>
      <description>&lt;p&gt;Last year, the React team announced hooks, a feature to more easily abstract
logic into reusable components. On the day of the announcement,
&lt;a href=&quot;https://medium.com/@seanmcp/refactoring-a-render-prop-with-hooks-fc22ed537199&quot;&gt;I wrote and article&lt;/a&gt;
explaining how to refactor a render prop component with hook.&lt;/p&gt;
&lt;p&gt;Starting this week with release of
&lt;a href=&quot;https://reactjs.org/blog/2019/02/06/react-v16.8.0.html&quot;&gt;React v16.8&lt;/a&gt;, &lt;strong&gt;you can
now add hooks in your projects&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Today, I want to look at a typical class component and demonstrate how you can
covert it into a functional component with React hooks. Let&#39;s jump in.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;terminology&quot; tabindex=&quot;-1&quot;&gt;Terminology&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#terminology&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Terminology”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: Skip this section if you&#39;re familiar with class and functional React
components.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I&#39;m going to use the terms &amp;quot;class&amp;quot; and &amp;quot;functional&amp;quot; components to refer to the
modern options for creating components. A class component looks something like
this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ClassExample&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;greeting&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;greeting&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Class components have access to internal state; default, custom, and lifecycle
methods; and a &lt;code&gt;this&lt;/code&gt; to reference. These components have been the powerhouses
of React development throughout its history.&lt;/p&gt;
&lt;p&gt;The aptly named functional components are functions that return JSX. Here&#39;s a
typical example:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;FunctionalExample&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; greeting &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Howdy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;greeting&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Functional components lack an internal state, methods, and &lt;code&gt;this&lt;/code&gt;. In order to
access passed props, we refer to the &lt;code&gt;props&lt;/code&gt; parameter.&lt;/p&gt;
&lt;p&gt;Because they contain less internal logic, functional components are sometimes
referred to as &amp;quot;dumb&amp;quot; or &amp;quot;presentational&amp;quot; components.&lt;/p&gt;
&lt;p&gt;Although different in composition, class and functional components are used in
the same manner. Let&#39;s reference both examples from above in a hypothetical
parent component:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ClassExample name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Sean&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;FunctionalExample name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;partner&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the parent&#39;s perspective, the two types of components are identical. To
understand how React internally understands and processes these two different
types of components, I recommend Dan Abramov&#39;s
&lt;a href=&quot;https://overreacted.io/how-does-react-tell-a-class-from-a-function/&quot;&gt;&amp;quot;How Does React Tell a Class from a Function?&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These are simplified definitions and examples, but they will provide us with a
good basis for the rest of the article.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;class-component&quot; tabindex=&quot;-1&quot;&gt;Class component&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#class-component&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Class component”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I have a component that makes an API request on mount, stores the response in
state, then renders some JSX based on the data. Here&#39;s the code:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ClassComponent&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;componentDidMount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://random.dog/woof.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Doggo&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;img src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; alt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A cute dog&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Fetching&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: To create this example, I looked through Todd Motto&#39;s awesome list of
&lt;a href=&quot;https://github.com/toddmotto/public-apis&quot;&gt;&amp;quot;Public APIs&amp;quot;&lt;/a&gt;. Check it out and give
it a star if you find it useful.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I used the fetch library to keep the example straight forward (and it seemed
fitting for an app that displays dog photos), but I recommend using a more
robust option like &lt;a href=&quot;https://github.com/axios/axios&quot;&gt;Axios&lt;/a&gt; with better error
handling for your applications.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;functional-component&quot; tabindex=&quot;-1&quot;&gt;Functional Component&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#functional-component&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Functional Component”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Using React Hooks, we can create the same example from above using a functional
component.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;setup&quot; tabindex=&quot;-1&quot;&gt;Setup&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#setup&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Setup”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;First, we&#39;ll create a new file for our functional code and set up a basic
function. Then copy the &lt;code&gt;return&lt;/code&gt; from our class component and remove all
references to &lt;code&gt;this.state&lt;/code&gt;. We need to declare a variable to prevent reference
errors, so let&#39;s call it &lt;code&gt;url&lt;/code&gt;.&lt;/p&gt;
&lt;!-- ```js/1,3-6 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;FunctionalComponent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// We&#39;ll change this later&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Doggo&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;img src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; alt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A cute dog&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Fetching&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;useeffect&quot; tabindex=&quot;-1&quot;&gt;useEffect&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#useeffect&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “useEffect”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In our class component, we make an AJAX request when the component mounted and
stored that data in state. &lt;code&gt;componentDidMount&lt;/code&gt; and the other lifecycle methods
are limited to classes. However, the React team was able to implement those
features with the &lt;code&gt;useEffect&lt;/code&gt; hook.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; is a method that takes two parameters: 1) a function to call on
mount, and 2) an array of variables to watch for updating.&lt;/p&gt;
&lt;p&gt;For the first parameter, we&#39;ll pass an anonymous function that calls fetch,
processes the data, and logs the response. The second argument just be an empty
array for now.&lt;/p&gt;
&lt;!-- ```js/2-6 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;FunctionalComponent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://random.dog/woof.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Doggo&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;img src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; alt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A cute dog&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Fetching&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are coding along, you should see something like the following in your
console when the component mounts:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{ &amp;quot;url&amp;quot;: &amp;quot;https://random.dog/867580b3d005.jpg&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This shows us that our API call is working, but logging the response isn&#39;t our
goal; we need to store the data for later. Let&#39;s revisit the &lt;code&gt;url&lt;/code&gt; variable that
we created.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;usestate&quot; tabindex=&quot;-1&quot;&gt;useState&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#usestate&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “useState”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Now that we have the response from our API, we need to be able to capture and
reference that value. In our class component, we used its state and the
&lt;code&gt;setState&lt;/code&gt; method to remember that data.&lt;/p&gt;
&lt;p&gt;React&#39;s &lt;code&gt;useState&lt;/code&gt; hook gives us access to a similar API without using a class.
When calling the function and optionally passing a default value, we receive two
returned variables: 1) a reference to the value, and 2) a function to update
that value, respectively.&lt;/p&gt;
&lt;p&gt;Using array destructuring, we can grab those variables and assign a name
according to the convention: &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;setX&lt;/code&gt;. For our example, we&#39;ll call the
value &lt;code&gt;url&lt;/code&gt; and the setter function &lt;code&gt;setUrl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;ll replace our old &lt;code&gt;url&lt;/code&gt; with the results from &lt;code&gt;useState&lt;/code&gt;:&lt;/p&gt;
&lt;!-- ```js/1 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;FunctionalComponent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setUrl&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://random.dog/woof.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Doggo&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;img src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; alt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A cute dog&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Fetching&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using &lt;code&gt;useState&lt;/code&gt;, we can quickly add basic state to our functional component.&lt;/p&gt;
&lt;p&gt;In the code above, we&#39;re just logging the response from our API. Now we want to
use the &lt;code&gt;setUrl&lt;/code&gt; function to set the value or url in our component&#39;s state.&lt;/p&gt;
&lt;!-- ```js/5 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;FunctionalComponent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setUrl&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://random.dog/woof.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Doggo&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;img src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; alt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A cute dog&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Fetching&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&#39;s take a second to revisit the second parameter passed to &lt;code&gt;useEffect&lt;/code&gt;.
Remember, it contains a list of variables that will trigger the effect to run
again on change.&lt;/p&gt;
&lt;p&gt;Our effect depends on one outside variable: &lt;code&gt;setUrl&lt;/code&gt;. This function is generated
once by &lt;code&gt;useState&lt;/code&gt;, and adding it to the array will ensure that our fetch call
isn&#39;t fired repeatedly.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;!-- ```js/6 --&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;FunctionalComponent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setUrl&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://random.dog/woof.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; raw&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;setUrl&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Doggo&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;img src&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; alt&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A cute dog&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Fetching&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;section&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s it! Checkout the &lt;a href=&quot;https://codesandbox.io/s/wwvmq1v407&quot;&gt;live example&lt;/a&gt; on
CodeSandbox to see the two components side-by-side.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;comparison&quot; tabindex=&quot;-1&quot;&gt;Comparison&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#comparison&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Comparison”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Let&#39;s take a moment and consider our two components. The new functional
component is a little shorter than the original class component, and the
variables are shorter and easier to reference.&lt;/p&gt;
&lt;p&gt;Those are nice benefits, but I don&#39;t find either a convincing reason to go back
and convert all my class components.&lt;/p&gt;
&lt;p&gt;More important to me is the fact that &lt;strong&gt;you can now use a functional component
for nearly everything in your application&lt;/strong&gt;. Since every component is
functional, it makes the process of bringing in or removing state and lifecycle
effects much easier.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;embrace-the-class-less-future&quot; tabindex=&quot;-1&quot;&gt;Embrace the class-less future&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#embrace-the-class-less-future&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Embrace the class-less future”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;For those reasons and others, the future of React is class-less. And that&#39;s a
good thing. Hooks provide more flexibility when creating and managing
components, to say nothing of
&lt;a href=&quot;https://reactjs.org/docs/hooks-custom.html&quot;&gt;custom hooks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But don&#39;t panic and convert all your class components right now;
&lt;a href=&quot;https://twitter.com/dan_abramov/status/1026839679197437953&quot;&gt;&amp;quot;they&#39;ll be supported for a looooong time&amp;quot;&lt;/a&gt;.
However, when you have the opportunity to refactor a class component going
forward, consider converting it into a functional component with hooks.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;A big thanks to &lt;a href=&quot;https://medium.com/@hungtrn75&quot;&gt;Hung Tran Van&lt;/a&gt; on Medium for
&lt;a href=&quot;https://medium.com/@hungtrn75/an-infinite-loop-when-u-set-url-state-in-useeffect-efc4426ef4ce&quot;&gt;highlighting a previous issue with this article&lt;/a&gt;.
While fixing my mistake, I found
&lt;a href=&quot;https://daveceddia.com/useeffect-hook-examples/&quot;&gt;&lt;em&gt;How the useEffect Hook Works&lt;/em&gt;&lt;/a&gt;
by David Ceddia to be super helpful. &lt;a href=&quot;https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Wed, 06 Feb 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/convert-class-component-to-function-with-hooks/</guid>
    </item>
    <item>
      <title>Accessibility Wednesday</title>
      <link>https://seanmcp.com/articles/accessibility-wednesday/</link>
      <description>&lt;p&gt;In the fall of 2018, I had the good pleasure of attending the
&lt;a href=&quot;https://connect.tech&quot;&gt;Connect.Tech&lt;/a&gt; conference in Atlanta, GA. There were great
talks about React, user experience design, and exciting new features for
JavaScript.&lt;/p&gt;
&lt;p&gt;But the sessions that had the greatest impact on me were all focused on
accessibility.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;accessibility-is-important&quot; tabindex=&quot;-1&quot;&gt;Accessibility is important&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/accessibility-wednesday/#accessibility-is-important&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Accessibility is important”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;It might seem obvious to you, but I needed to hear that loudly proclaimed from
the keynote stage.&lt;/p&gt;
&lt;p&gt;Accessibility isn&#39;t just about our friends and neighbors with disabilities; it&#39;s
about making applications that work well for everyone.
&lt;a href=&quot;https://ssir.org/articles/entry/the_curb_cut_effect&quot;&gt;The Curb Cut Effect&lt;/a&gt; is a
perfect example about how accommodations make everyone&#39;s lives easier.&lt;/p&gt;
&lt;p&gt;I was treating accessibility as if it was icing on a cake--something that was
nice to have but not essential. Unfortunately, it was that type of thinking that
allows inaccessible apps to flourish.&lt;/p&gt;
&lt;p&gt;Accessibility is not a feature; it&#39;s part of the product. If our app isn&#39;t
accessible, then it isn&#39;t done.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;%22whoa%2C-what-was-i-doing-before%3F%22&quot; tabindex=&quot;-1&quot;&gt;&amp;quot;Whoa, what was I doing before?&amp;quot;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/accessibility-wednesday/#%22whoa%2C-what-was-i-doing-before%3F%22&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “&amp;quot;Whoa, what was I doing before?&amp;quot;”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Hearing all that was like a light switch being flipped in my mind--and with that
came loads of guilt and regret for all the neighbors I had neglected for the
decade I had been developing. I felt especially convicted by my experiences in
my previous career.&lt;/p&gt;
&lt;p&gt;Before becoming a developer, I studied education in college and spent three
years working as a teacher. The importance of creating an inclusive environment
and the value of accommodations was drilled into us early on, and we studied how
great accommodations increase learning outcomes for all students.&lt;/p&gt;
&lt;p&gt;Further yet, I had seen those benefits first hand while working in over a dozen
schools across Pennsylvania and Georgia.&lt;/p&gt;
&lt;p&gt;If accessibility was so important to my previous career, why wouldn&#39;t it be the
same in my new one as a developer?&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;%22okay...-now-what%3F%22&quot; tabindex=&quot;-1&quot;&gt;&amp;quot;Okay... now what?&amp;quot;&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/accessibility-wednesday/#%22okay...-now-what%3F%22&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “&amp;quot;Okay... now what?&amp;quot;”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Impressed with a sudden desire to make all the things accessible, I left the
conference and looked online for resources to help.&lt;/p&gt;
&lt;p&gt;I first tried to read the
&lt;a href=&quot;https://www.w3.org/TR/WCAG21/&quot;&gt;Web Content Accessibility Guidelines 2.1&lt;/a&gt;, which
weren&#39;t as difficult to grasp as I had feared. Even so, the content was dense
and a tough slog for a newbie.&lt;/p&gt;
&lt;p&gt;Seeking more digestible information, I found other resources on W3C to be
helpful, especially
&lt;a href=&quot;https://www.w3.org/WAI/roles/developers/&quot;&gt;those specifically for developers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was working with React Native at the time, so I created
&lt;a href=&quot;https://github.com/SeanMcP/awesome-react-native-accessibility&quot;&gt;Awesome React Native Accessibility&lt;/a&gt;,
a repo with a list of mobile-specific resources. Progress on that halted when I
switched to a React project at work.&lt;/p&gt;
&lt;p&gt;At this point, I was starting to feel a little overwhelmed. Everywhere I looked
were categories, rules, laws, practices, and oodles of examples of companies
doing it wrong. It all seemed like too much.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;accessibility-is-hard&quot; tabindex=&quot;-1&quot;&gt;Accessibility is hard&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/accessibility-wednesday/#accessibility-is-hard&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Accessibility is hard”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I was beginning to think that maybe accessibility was too difficult, too
technical, too intricate for me. And I&#39;m sure that I am not alone in having
thought that.&lt;/p&gt;
&lt;p&gt;But the reality is that developing for accessibility is a skill. And just like
any other skill, it requires little bites and regular practice. Over time you
will improve, and eventually what seemed difficult will become second nature.&lt;/p&gt;
&lt;p&gt;There is a reason we don&#39;t learn to walk by running. Our brains weren&#39;t designed
to work that way. As the father of a now-cruising baby, I feel particularly
qualified to say that learning to walk is hard work. It&#39;s filled with failures,
bumps, and bruises. Same with riding a bike, learning to read, or adjusting to a
AAC device.&lt;/p&gt;
&lt;p&gt;You will fail at first (and second and third), but as long as you persevere, you
can be successful. You can learn. You can grow.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;let&#39;s-learn-about-accessibility&quot; tabindex=&quot;-1&quot;&gt;Let&#39;s learn about accessibility&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/accessibility-wednesday/#let&#39;s-learn-about-accessibility&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Let&#39;s learn about accessibility”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I am determined: I want to become an accessible developer. I want to bake
accessibility in for as many neighbors as possible into every application on
which I work.&lt;/p&gt;
&lt;p&gt;In order to meet that goal, I need to learn more about accessibility. And that&#39;s
where this article comes in. This is the kick-off to a series called
&amp;quot;Accessibility Wednesday&amp;quot; where I will share accessibility tid-bits for
developers.&lt;/p&gt;
&lt;p&gt;These won&#39;t be full articles--neither you nor I have time for that. Rather, I&#39;ll
share images, links, and code samples on Twitter with the hashtag
&lt;a href=&quot;https://twitter.com/hashtag/a11ywednesday&quot;&gt;#a11ywednesday&lt;/a&gt;. Everything will be
available in &lt;a href=&quot;https://github.com/SeanMcP/accessibility-wednesday&quot;&gt;a GitHub repo&lt;/a&gt;
for easy reference.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;remember%3A-i&#39;m-no-expert-(yet)&quot; tabindex=&quot;-1&quot;&gt;Remember: I&#39;m no expert (yet)&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/accessibility-wednesday/#remember%3A-i&#39;m-no-expert-(yet)&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Remember: I&#39;m no expert (yet)”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Since I am not an authoritative resource on accessibility, I will make sure to
include references and citations to every applicable tidbit. Is MLA formatting
still a thing? (s/o PurdueOWL)&lt;/p&gt;
&lt;p&gt;This is a learning exercise for me as much as it is for everyone else. With that
in mind, I will almost certainly make mistakes. All of us fall short of the
target. That&#39;s why I encourage you to help me correct my mistakes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/SeanMcP/accessibility-wednesday/issues/new&quot;&gt;File an issue&lt;/a&gt;
on GitHub referencing the tip in question, or--better yet--make a pull request
with the fix. I happily welcome any and all contributions the the project.&lt;/p&gt;
&lt;p&gt;If you notice the mistake &lt;a href=&quot;https://twitter.com/snmcp&quot;&gt;on Twitter&lt;/a&gt;, please
respond or direct message to let me know. I will remove the tweet, make the
correction, and share the updated information later.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;stronger-together&quot; tabindex=&quot;-1&quot;&gt;Stronger together&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/accessibility-wednesday/#stronger-together&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Stronger together”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;As time goes on, I&#39;m hoping that Accessibility Wednesday grows into a catalog of
useful information for developers of all levels to make more accessible
applications. We know that there is power in our collective knowledge.&lt;/p&gt;
&lt;p&gt;As a wise man once penned, &amp;quot;with great power there must also come--great
responsibility!&amp;quot;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/accessibility-wednesday/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; Let&#39;s use our power for good and make the web more
accessible for everyone.&lt;/p&gt;
&lt;p&gt;Join the discussion &lt;a href=&quot;https://twitter.com/hashtag/a11ywednesday&quot;&gt;on Twitter&lt;/a&gt; or
&lt;a href=&quot;https://github.com/SeanMcP/accessibility-wednesday&quot;&gt;GitHub&lt;/a&gt;. I look forward to
learning and sharing with you all!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I learned while writing this article that the original phrase from
Spider-Man is slightly different than the modern variation.
&lt;a href=&quot;http://www.quotecounterquote.com/2012/07/with-great-power-comes-great.html&quot;&gt;(source)&lt;/a&gt; &lt;a href=&quot;https://seanmcp.com/articles/accessibility-wednesday/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Wed, 06 Feb 2019 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/accessibility-wednesday/</guid>
    </item>
    <item>
      <title>How to create a render prop component</title>
      <link>https://seanmcp.com/articles/create-a-render-prop-component/</link>
      <description>&lt;p&gt;It&#39;s been a year since Michael Jackson published &amp;quot;Use a Render Prop!&amp;quot;, which
encouraged using render props instead of higher order components (HOCs). Since
then, &amp;quot;render props&amp;quot; has grown into a bigger and bigger buzzword in the React
community.&lt;/p&gt;
&lt;p&gt;If you are new to React or just new to the concept, the look of a render prop
can be a little daunting.
&lt;a href=&quot;https://www.react-spring.io/docs/props/spring&quot;&gt;Checkout this example from &lt;code&gt;react-spring&lt;/code&gt;&lt;/a&gt;&#39;s
documentation:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Spring &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-spring&#39;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Spring from&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; to&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;styles&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;i will fade &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &amp;lt;-- Here&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Spring&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If that makes perfect sense to you, awesome 🎉! Skip this article and get back
to coding. If not, don&#39;t worry; I didn&#39;t get it at first either. Stick around,
and I&#39;ll attempt to break down render props and show you how to make your own.&lt;/p&gt;
&lt;hr&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;background&quot; tabindex=&quot;-1&quot;&gt;Background&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#background&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Background”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;what-is-a-render-prop%3F&quot; tabindex=&quot;-1&quot;&gt;What is a render prop?&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#what-is-a-render-prop%3F&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “What is a render prop?”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;At its core, render prop is &amp;quot;a simple technique for sharing code between React
components using a prop whose value is a function.&amp;quot;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; Instead of passing a
string or object, you pass a function as a prop.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Name renderProp&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Passing a function as a prop!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above won&#39;t accomplish much - the arrow function just returns a
string - but it introduces a new paradigm. What if, within &lt;code&gt;Name&lt;/code&gt; we pass some
data to our &lt;code&gt;props.renderProp&lt;/code&gt; function?&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Sean&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderProp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When &lt;code&gt;Name&lt;/code&gt; renders, it calls &lt;code&gt;props.renderProp&lt;/code&gt; and passes some data; in this
case, a string with my name.&lt;/p&gt;
&lt;p&gt;We have designed our &lt;code&gt;Name&lt;/code&gt; component with the sole purpose of storing the
&lt;code&gt;name&lt;/code&gt; data and passing it on to the &lt;code&gt;props.renderProps&lt;/code&gt; function. The is the
secret sauce that makes render props so powerful.&lt;/p&gt;
&lt;p&gt;Going back to the implementation of &lt;code&gt;Name&lt;/code&gt;, the function I pass to &lt;code&gt;renderProp&lt;/code&gt;
can look for this data as a parameter:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Name renderProp&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;Hello, my name is &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When &lt;code&gt;Nam&lt;/code&gt;e is called, it creates variable &lt;code&gt;name&lt;/code&gt; with the value &#39;Sean&#39;, then
calls the &lt;code&gt;props.renderProp&lt;/code&gt; function and passes &lt;code&gt;name&lt;/code&gt;. Finally, it returns a
string that reads &lt;code&gt;Hello, my name is Sean!&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But we aren&#39;t just limited to strings; this is React! You can return JSX in your
function to render new elements in the VirtualDOM:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Name renderProp&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; my name is &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s it! Render props provide us a method of passing props from a parent
component to a child via function props. Using these same principles, we can
create useful and reusable &amp;quot;logic&amp;quot; components to implement in any application.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: I called our prop &lt;code&gt;renderProp&lt;/code&gt;, but there is nothing special about that
name; you can use whatever name you want. I&#39;ll give you my recommendation for
passing function props later on.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;what-does-render-props-replace%3F&quot; tabindex=&quot;-1&quot;&gt;What does render props replace?&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#what-does-render-props-replace%3F&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “What does render props replace?”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;In most use cases, render props will replace HOCs. If we wanted to accomplish
the above example with an HOC, we might use something like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;withName&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Component name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Sean&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then our parent component would be passed to &lt;code&gt;withName&lt;/code&gt;, usually during the
export. Once that is done, we could access &lt;code&gt;props.name&lt;/code&gt; and render our greeting:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; my name is &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;span&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;withName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;App&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works, and certainly has
&lt;a href=&quot;https://medium.com/r/?url=https%3A%2F%2Freact-redux.js.org%2Fdocs%2Fconnect-extracting-data-with-mapstatetoprops&quot;&gt;its use cases&lt;/a&gt;,
but can introduce issues such as naming collisions. I recommend
&lt;a href=&quot;https://medium.com/r/?url=https%3A%2F%2Fcdb.reacttraining.com%2Fuse-a-render-prop-50de598f11ce&quot;&gt;Jackson&#39;s article for a more detailed dive into render props and HOCs&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;how-to&quot; tabindex=&quot;-1&quot;&gt;How To&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#how-to&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “How To”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Note: Facebook provides an
&lt;a href=&quot;https://medium.com/r/?url=https%3A%2F%2Freactjs.org%2Fdocs%2Frender-props.html&quot;&gt;introduction to render props in their React documentation&lt;/a&gt;.
It is a useful resource, but their example was contrived and therefore difficult
to reapply to new scenarios. Here I will provide a tried-and-true example that I
have utilized in multiple projects.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;setting-up-our-app&quot; tabindex=&quot;-1&quot;&gt;Setting up our app&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#setting-up-our-app&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Setting up our app”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Let&#39;s imagine you&#39;re creating an application with drawer menu. Most of the time
the menu is hidden, but when you hit a toggle button, the menu opens. Within the
menu, you want to have an accordion that reveals additional links when open. In
order to accomplish this, you might do something like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;menuIsOpen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;app&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;menuIsOpen &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Menu toggle&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token constant&quot;&gt;MENU&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;toggle&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;menuIsOpen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;menuIsOpen &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We made &lt;code&gt;App&lt;/code&gt; a stateful component and keep track of a boolean for the menu.
Additionally, we added a &lt;code&gt;toggle&lt;/code&gt; method to open and close the menu.&lt;/p&gt;
&lt;p&gt;Now we need to create Menu:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Menu&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;socialsIsOpen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;menu&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;CLOSE&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Menu&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;SOCIALS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;socialsIsOpen &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;▴&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;▾&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;socialsIsOpen &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Socials &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;toggle&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;socialsIsOpen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;socialsIsOpen &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look familiar? We &lt;strong&gt;reused the state from &lt;code&gt;App&lt;/code&gt;&lt;/strong&gt; (🚩 red flag no 1) so that we
could keep track of whether or not to display our &lt;code&gt;Socials&lt;/code&gt; component (just an
unordered list of links). &lt;code&gt;Menu&lt;/code&gt; needed to be toggled too, so we &lt;strong&gt;copy and
pasted the method from &lt;code&gt;App&lt;/code&gt;&lt;/strong&gt; (🚩 red flag no. 2).&lt;/p&gt;
&lt;p&gt;This works, but there are two main problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;👎 &lt;strong&gt;Not DRY&lt;/strong&gt;: In order to achieve the same function in two different
components, I needed to repeat myself by copying and pasting the state and
toggle method.&lt;/li&gt;
&lt;li&gt;👎 &lt;strong&gt;Not extensible&lt;/strong&gt;: Imagine I want to add another toggle feature to my
app. What do I need to do? Copy and paste the necessary state and method
again, which compounds my problem.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Fortunately, we can solve both of these problems easily with a simple render
prop component.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;creating-a-render-prop&quot; tabindex=&quot;-1&quot;&gt;Creating a render prop&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#creating-a-render-prop&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Creating a render prop”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The purpose of our render prop component will be to manage an open and closed
state. It will also need a method to toggle the state like the examples above.
Then it will take the state and method and pass it as arguments to a prop.&lt;/p&gt;
&lt;p&gt;My preference for render props is to use a Component&#39;s &lt;code&gt;children&lt;/code&gt; prop. This
allows us to utilize opening and closing tags - a familiar convention in
React - and makes indentation a little more manageable.&lt;/p&gt;
&lt;p&gt;Our render prop component looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Open&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  state &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;isOpen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function-variable function&quot;&gt;toggle&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;isOpen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; renderProps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;isOpen&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;toggle&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;children &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;function&quot;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderProps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;children&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just like the previous examples, I am keeping track of an &amp;quot;open&amp;quot; state and
toggling it with a method. Here I simplified the name of the boolean in the
state to &lt;code&gt;isOpen&lt;/code&gt; because our component doesn&#39;t care what is and is not open.
The only thing &lt;code&gt;Open&lt;/code&gt; cares about is whether or not &lt;code&gt;isOpen&lt;/code&gt; is true or false.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Render props components do not care about presentational logic. Their sole
purpose is to keep track of simple bits of data and pass it on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code&gt;toggle&lt;/code&gt; method is the same as previous examples.&lt;/p&gt;
&lt;p&gt;Within the &lt;code&gt;render&lt;/code&gt; method, I create a &lt;code&gt;renderProps&lt;/code&gt; object with which I can
pass on the current value of &lt;code&gt;isOpen&lt;/code&gt; and my &lt;code&gt;toggle&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;Finally I do a quick &lt;code&gt;typeof&lt;/code&gt; check while returning. If &lt;code&gt;this.props.children&lt;/code&gt; is
a function, as I expect, then it will pass &lt;code&gt;renderProps&lt;/code&gt; as an argument. If not,
then it will fail softly by simply returning &lt;code&gt;this.props.children&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can optionally do some type-checking to ensure that &lt;code&gt;children&lt;/code&gt; is a
function, but I chose not to add an additional library here.&lt;/p&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h3 id=&quot;implementing-our-render-prop&quot; tabindex=&quot;-1&quot;&gt;Implementing our render prop&lt;/h3&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#implementing-our-render-prop&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Implementing our render prop”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Now that we have abstracted the open/close logic to &lt;code&gt;Open&lt;/code&gt;, we can clean up our
App component:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Open&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;openProps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;app&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;openProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;NewMenu toggle&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;openProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;openProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
            &lt;span class=&quot;token constant&quot;&gt;MENU&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Welcome &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;main&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Open&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We pass &lt;code&gt;Open&lt;/code&gt; a child function that looks for our render props. Now I just need
to switch out all references to &lt;code&gt;this.state.menuIsOpen&lt;/code&gt; and &lt;code&gt;this.toggle&lt;/code&gt; to
refer to &lt;code&gt;openProps&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Notice that &lt;code&gt;App&lt;/code&gt; no longer needs a state; we can convert it to a functional
component and let &lt;code&gt;Open&lt;/code&gt; do all the work.&lt;/p&gt;
&lt;p&gt;Next, let&#39;s do the same thing with &lt;code&gt;Menu&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Menu&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Open&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;openProps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;menu&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;CLOSE&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Menu&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;button onClick&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;openProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;toggle&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
          &lt;span class=&quot;token constant&quot;&gt;SOCIALS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;openProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;▴&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;▾&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;button&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;openProps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isOpen &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Socials &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Open&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Likewise, we were able to simplify Menu by converting it to a functional
component as well. This may not seem like a big deal now, but it will be
increasingly important as an application scales.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The fewer states and methods that you need to manage, the better.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can see our render prop live, in all its glory, here on CodeSandbox:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/x5j1pl90o?fontsize=14&amp;hidenavigation=1&amp;theme=dark&amp;view=preview&quot; style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot; title=&quot;How to create a render prop component&quot; allow=&quot;geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb&quot; sandbox=&quot;allow-modals allow-forms allow-popups allow-scripts allow-same-origin&quot;&gt;&lt;/iframe&gt;
&lt;div class=&quot;heading-container&quot;&gt;
&lt;h2 id=&quot;review&quot; tabindex=&quot;-1&quot;&gt;Review&lt;/h2&gt;
&lt;a class=&quot;header-anchor&quot; href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#review&quot;&gt;&lt;span class=&quot;visually-hidden&quot;&gt;Permalink to “Review”&lt;/span&gt; &lt;span aria-hidden=&quot;true&quot;&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;The render props technique is a great way to abstract reusable logic into
specialized components. These components pass their logic/data/methods as
arguments to functions passed as props.&lt;/p&gt;
&lt;p&gt;Utilizing render props components solves the two problems above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;👍 &lt;strong&gt;DRY&lt;/strong&gt;: The only code repeated is &lt;code&gt;&amp;lt;Open&amp;gt;&lt;/code&gt;. You&#39;ll never have to write
another &lt;code&gt;toggle&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;👍 &lt;strong&gt;Extensible&lt;/strong&gt;: Next time you want to add opening and closing to your app,
all you need to add is &lt;code&gt;Open&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now that we&#39;ve reviewed, let&#39;s take a look back at that original example from
&lt;code&gt;react-spring&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Spring &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-spring&#39;&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Spring from&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; to&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;styles&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;styles&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;i will fade &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &amp;lt;-- Here&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Spring&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that this &lt;code&gt;Spring&lt;/code&gt; component is passed a &lt;code&gt;this.props.children&lt;/code&gt;
function. It then gives some data, in this case a style object, to that function
as an argument. Finally, those &lt;code&gt;styles&lt;/code&gt; are applied to the &lt;code&gt;div&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Not bad, right? Now that you&#39;ve mastered render props, make sure to check out
this curated list of awesome render props. In the words of Captain Planet, &amp;quot;The
power is yours!&amp;quot;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I hope this article helped; I know I learned a lot while writing it. Let me know
if you have any &lt;a href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#comment-link&quot;&gt;questions about or problems&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://reactjs.org/docs/render-props.html&quot;&gt;https://reactjs.org/docs/render-props.html&lt;/a&gt; &lt;a href=&quot;https://seanmcp.com/articles/create-a-render-prop-component/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</description>
      <pubDate>Tue, 09 Oct 2018 16:00:00 GMT</pubDate>
      <dc:creator>Sean McPherson</dc:creator>
      <guid>https://seanmcp.com/articles/create-a-render-prop-component/</guid>
    </item>
  </channel>
</rss>