<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Dennis Morello</title>
    <description>The latest articles on Forem by Dennis Morello (@morellodev).</description>
    <link>https://forem.com/morellodev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F219117%2F1f9c2fb4-774c-4736-a658-17104c6ba25d.JPG</url>
      <title>Forem: Dennis Morello</title>
      <link>https://forem.com/morellodev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/morellodev"/>
    <language>en</language>
    <item>
      <title>Configuring My Site for AI Discoverability</title>
      <dc:creator>Dennis Morello</dc:creator>
      <pubDate>Tue, 21 Apr 2026 08:02:58 +0000</pubDate>
      <link>https://forem.com/morellodev/configuring-my-site-for-ai-discoverability-1j38</link>
      <guid>https://forem.com/morellodev/configuring-my-site-for-ai-discoverability-1j38</guid>
      <description>&lt;p&gt;A growing share of web traffic doesn't come from people anymore. It comes from models reading on their behalf. ChatGPT, Claude, Perplexity, Copilot. They fetch a handful of pages, summarize, and ship the answer back. If your site isn't readable by those agents, you don't exist to them.&lt;/p&gt;

&lt;p&gt;People are calling this &lt;a href="https://wikipedia.org/wiki/Generative_engine_optimization" rel="noopener noreferrer"&gt;GEO&lt;/a&gt;, short for Generative Engine Optimization. It overlaps with SEO but the priorities are different. Agents don't care about your layout. They care about your prose, your metadata, and how many tokens it costs them to read you.&lt;/p&gt;

&lt;p&gt;This post covers how I configured this site for GEO. The first half is framework-agnostic. The second half is specific to my setup on Cloudflare, and includes a deliberate choice that fails a popular GEO audit. I'll explain why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: general GEO techniques
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Serve raw Markdown alongside HTML
&lt;/h3&gt;

&lt;p&gt;The single biggest GEO win is giving agents a version of each page without the navigation, styling, and scripts. HTML is designed for browsers. Markdown is designed for readers, human or otherwise. Agents spend their context window on your prose, not your DOM.&lt;/p&gt;

&lt;p&gt;Every blog post on this site has a mirror URL with a &lt;code&gt;.md&lt;/code&gt; suffix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/blog/my-post&lt;/code&gt; is the full HTML page for humans&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/blog/my-post.md&lt;/code&gt; is the raw Markdown, served as &lt;code&gt;text/markdown&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Astro, this is a two-line route at &lt;code&gt;src/pages/blog/[slug].md.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPostById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatPostMarkdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/markdown; charset=utf-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both variants are pre-generated at build time. Same content, &lt;strong&gt;roughly half the tokens&lt;/strong&gt; for an agent to consume.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advertise the Markdown version in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Agents landing on the HTML need to know the Markdown exists. A single &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; in the head does it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/markdown"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/blog/my-post.md"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browsers ignore this tag. Agents that parse the head follow it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Publish an &lt;code&gt;llms.txt&lt;/code&gt; index
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://llmstxt.org/" rel="noopener noreferrer"&gt;&lt;code&gt;llms.txt&lt;/code&gt;&lt;/a&gt; is a convention for a Markdown file at the root of your site listing your content with short descriptions and links. Think of it as a sitemap an LLM can actually read.&lt;/p&gt;

&lt;p&gt;I ship two variants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/llms.txt&lt;/code&gt; is the index. Title, description, one line per post with a link to its &lt;code&gt;.md&lt;/code&gt; version.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/llms-full.txt&lt;/code&gt; is the full corpus. Every post body concatenated into a single response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why both? An agent researching a specific topic can fetch &lt;code&gt;llms.txt&lt;/code&gt;, pick the relevant links, and pull them. An agent doing deep research on the site as a whole fetches &lt;code&gt;llms-full.txt&lt;/code&gt; once and has everything it needs in one request. Either way there's no crawling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Declare your AI stance in &lt;code&gt;robots.txt&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;robots.txt&lt;/code&gt; now carries a &lt;code&gt;Content-Signal&lt;/code&gt; directive for AI use. Mine reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-agent: *
Content-Signal: search=yes, ai-train=no, ai-input=yes
Allow: /
Sitemap: https://morello.dev/sitemap-index.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three independent knobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;search=yes&lt;/code&gt; lets search engines index&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ai-train=no&lt;/code&gt; says my content is not for training data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ai-input=yes&lt;/code&gt; says my content &lt;em&gt;can&lt;/em&gt; be retrieved and used as input for AI answers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the stance I'm comfortable with. I want to show up when someone asks Claude about something I've written; I just don't want my posts absorbed into the next base model.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Whether any given operator actually honors this is another question. The signal's there regardless, and I'd rather be on record than silent about it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Add structured data that actually describes the content
&lt;/h3&gt;

&lt;p&gt;Most blogs ship JSON-LD schema by reflex. Few of them include the fields that help a generative engine decide whether your article is worth fetching.&lt;/p&gt;

&lt;p&gt;On each post I emit a &lt;code&gt;BlogPosting&lt;/code&gt; graph with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;wordCount&lt;/code&gt; and &lt;code&gt;timeRequired&lt;/code&gt; (ISO 8601 duration), so an agent can estimate how much context it'll spend before fetching&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;articleBody&lt;/code&gt;, the full text machine-readable, with no HTML parsing required&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;author&lt;/code&gt; linked to a &lt;code&gt;Person&lt;/code&gt; node with &lt;code&gt;knowsAbout&lt;/code&gt; so the entity is grounded in real topics&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BreadcrumbList&lt;/code&gt; for site hierarchy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of it goes into a single &lt;code&gt;@graph&lt;/code&gt; per page rather than scattered &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags, which makes it cheaper for an engine to walk from post to author to site without cross-referencing.&lt;/p&gt;

&lt;h3&gt;
  
  
  A sitemap that actually tracks freshness
&lt;/h3&gt;

&lt;p&gt;If you regenerate your sitemap once and never look at it again, you're wasting a signal. Every URL in mine carries a &lt;code&gt;lastmod&lt;/code&gt; timestamp pulled from the post's &lt;code&gt;updatedDate&lt;/code&gt; frontmatter, falling back to &lt;code&gt;pubDate&lt;/code&gt;. When I edit an old post, its &lt;code&gt;lastmod&lt;/code&gt; moves forward and crawlers reprioritize it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate with real tools
&lt;/h3&gt;

&lt;p&gt;Two tools I found useful while iterating on all of the above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://isitagentready.com/" rel="noopener noreferrer"&gt;isitagentready.com&lt;/a&gt; audits across five categories: discoverability, content accessibility, bot access control, protocol discovery, and commerce. The bot access control checks (&lt;code&gt;Content-Signal&lt;/code&gt;, Web Bot Auth, AI bot rules) are the part that actually influences how agents treat your content.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://acceptmarkdown.com/" rel="noopener noreferrer"&gt;acceptmarkdown.com&lt;/a&gt; has a narrower focus. It checks whether your site responds to &lt;code&gt;Accept: text/markdown&lt;/code&gt; with a Markdown body, includes &lt;code&gt;Vary: Accept&lt;/code&gt;, returns &lt;code&gt;406&lt;/code&gt; for unsupported types, and parses q-values correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll come back to the second one at the end of the post, because my site deliberately fails it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: the Cloudflare-specific setup
&lt;/h2&gt;

&lt;p&gt;General GEO gets you most of the way there. The rest is delivery. How fast you respond, whether the edge caches correctly, and how you advertise your agent-facing resources without waiting for someone to parse your HTML.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static assets, zero Worker invocations
&lt;/h3&gt;

&lt;p&gt;My &lt;code&gt;wrangler.jsonc&lt;/code&gt; points a &lt;code&gt;./dist&lt;/code&gt; directory at &lt;a href="https://developers.cloudflare.com/workers/static-assets/" rel="noopener noreferrer"&gt;Cloudflare's assets deployment&lt;/a&gt;, with no &lt;code&gt;main&lt;/code&gt; entry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"morellodev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compatibility_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"directory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"html_handling"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"drop-trailing-slash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"not_found_handling"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"404-page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every request goes straight from the edge asset cache. HTML, Markdown, &lt;code&gt;llms.txt&lt;/code&gt;, sitemap, RSS. Same path for all of them, and no Worker ever runs. On the Workers Free tier this matters. A crawler sweep that would otherwise eat into 100k daily invocations now costs me nothing. Agents, for better or worse, don't fingerprint politely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advertise discovery endpoints in a &lt;code&gt;Link&lt;/code&gt; header
&lt;/h3&gt;

&lt;p&gt;Cloudflare's &lt;a href="https://developers.cloudflare.com/workers/static-assets/headers/" rel="noopener noreferrer"&gt;&lt;code&gt;_headers&lt;/code&gt; file&lt;/a&gt; lets you ship response headers without any server code. I use it to tell every response, not just HTML ones, where the agent-facing files live:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
  Link: &amp;lt;/sitemap-index.xml&amp;gt;; rel="sitemap",
        &amp;lt;/rss.xml&amp;gt;; rel="alternate"; type="application/rss+xml"; title="RSS",
        &amp;lt;/llms.txt&amp;gt;; rel="describedby"; type="text/plain",
        &amp;lt;/llms-full.txt&amp;gt;; rel="describedby"; type="text/plain"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A crawler doing a &lt;code&gt;HEAD&lt;/code&gt; against any URL on the site sees all four links before it parses a single byte of HTML. &lt;strong&gt;One round-trip, no body, full discovery.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-lived cache for hashed assets
&lt;/h3&gt;

&lt;p&gt;Astro emits fingerprinted filenames under &lt;code&gt;/_astro/&lt;/code&gt;, so those can sit in cache for a year:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/_astro/*
  Cache-Control: public, max-age=31536000, immutable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Faster first paint for humans, cheaper crawls for agents. Same lever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I skipped &lt;code&gt;Accept: text/markdown&lt;/code&gt; content negotiation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://acceptmarkdown.com/" rel="noopener noreferrer"&gt;acceptmarkdown.com&lt;/a&gt; will tell you this site doesn't do content negotiation. No &lt;code&gt;Vary: Accept&lt;/code&gt;, no &lt;code&gt;406&lt;/code&gt;, no Markdown from the canonical URL. That's not an oversight. I tried it, shipped it briefly, and rolled it back.&lt;/p&gt;

&lt;p&gt;The reason is Cloudflare's free plan. Custom cache keys are Enterprise-only, and &lt;a href="https://developers.cloudflare.com/cache/concepts/cache-control/" rel="noopener noreferrer"&gt;their docs are explicit&lt;/a&gt; that &lt;code&gt;Vary: Accept&lt;/code&gt; is ignored for caching decisions. The edge collapses every variant of &lt;code&gt;/blog/my-post&lt;/code&gt; into one cache entry, so the first requester's format &lt;strong&gt;poisons the cache for everyone else&lt;/strong&gt; until TTL expires.&lt;/p&gt;

&lt;p&gt;The workaround is a Worker that bypasses the edge cache. But now every &lt;code&gt;/blog/*&lt;/code&gt; request burns a Worker invocation, humans included, and the &lt;a href="https://developers.cloudflare.com/workers/platform/pricing/" rel="noopener noreferrer"&gt;Workers Free plan&lt;/a&gt; gives you 100k per day and 10ms of CPU each. That's a real budget to share across humans and bots, for no functional gain over a static &lt;code&gt;.md&lt;/code&gt; URL.&lt;/p&gt;

&lt;p&gt;So I deleted the Worker. The only thing I lost is &lt;code&gt;curl -H "Accept: text/markdown" …/blog/my-post&lt;/code&gt; returning Markdown. Between &lt;code&gt;llms.txt&lt;/code&gt;, &lt;code&gt;&amp;lt;link rel="alternate"&amp;gt;&lt;/code&gt;, and the &lt;code&gt;/blog/[slug].md&lt;/code&gt; convention, no mainstream agent I've seen actually needs &lt;code&gt;Accept:&lt;/code&gt; negotiation. It's the more elegant protocol; alternate URLs are the more robust one on a free-tier CDN. On a paid plan I'd probably do both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this leaves things
&lt;/h2&gt;

&lt;p&gt;Every page exists in two forms, both served from the edge. Agent-facing resources are advertised in response headers on every request, before any HTML gets parsed. Structured data tells engines what the article is and how much context it takes to read. &lt;code&gt;robots.txt&lt;/code&gt; says what I'll allow and what I won't.&lt;/p&gt;

&lt;p&gt;GEO is still very new. The standards are half-drafted, the tools disagree with each other, and half the signals I described above didn't exist two years ago. I fully expect to be rewriting parts of this post within six months, probably with a different opinion about Accept-based negotiation, once I've either moved off the free plan or found a workaround that doesn't involve a Worker. But for now: serve agents a version they can cheaply consume, be explicit about what you'll allow, and accept that the defaults aren't on your side.&lt;/p&gt;

&lt;p&gt;If you're reading this via a summary from some assistant, hi. Thanks for the traffic.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>seo</category>
      <category>llm</category>
    </item>
    <item>
      <title>Git Worktrees Are Underrated</title>
      <dc:creator>Dennis Morello</dc:creator>
      <pubDate>Mon, 16 Mar 2026 22:07:48 +0000</pubDate>
      <link>https://forem.com/morellodev/git-worktrees-are-underrated-2k9</link>
      <guid>https://forem.com/morellodev/git-worktrees-are-underrated-2k9</guid>
      <description>&lt;p&gt;If you've ever stashed half-finished work to review a PR, or lost a train of thought switching branches, you should know about git worktrees. They've been in git since 2015, but most developers I talk to have never heard of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with branches
&lt;/h2&gt;

&lt;p&gt;The standard git workflow is linear. You're on a branch, you need to context-switch, so you stash your changes (or worse, make a throwaway commit), switch branches, do your thing, switch back, and pop the stash. If you're lucky, nothing conflicts.&lt;/p&gt;

&lt;p&gt;This gets worse when you're juggling multiple things at once. Reviewing a colleague's PR while your feature branch is mid-refactor. Running tests on one branch while coding on another. Hotfixing production while your main work sits frozen.&lt;/p&gt;

&lt;p&gt;A git repository has one working directory. One branch checked out at a time. Everything else has to wait.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worktrees
&lt;/h2&gt;

&lt;p&gt;Git worktrees let you check out multiple branches simultaneously, each in its own directory. They share the same &lt;code&gt;.git&lt;/code&gt; history and objects, so you're not cloning the entire repo, but each one has its own working directory and index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree add ../feat-login feat/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now &lt;code&gt;feat/login&lt;/code&gt; is checked out in &lt;code&gt;../feat-login&lt;/code&gt;. You can open it in a separate editor window, run tests there, or just let it sit while you work on something else.&lt;/p&gt;

&lt;p&gt;When you're done:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git worktree remove ../feat-login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Why nobody uses them
&lt;/h2&gt;

&lt;p&gt;If worktrees are so useful, why aren't they more popular? I think it comes down to two things.&lt;/p&gt;

&lt;p&gt;First, the directory problem. Every time you create a worktree, you have to pick a path. There's no convention for where they go. After a week you end up with directories scattered across your filesystem: &lt;code&gt;../feat-login&lt;/code&gt;, &lt;code&gt;~/tmp/hotfix-auth&lt;/code&gt;, &lt;code&gt;../../pr-review&lt;/code&gt;. Good luck remembering where anything is.&lt;/p&gt;

&lt;p&gt;Second, there are no ergonomics. You can't easily list your worktrees with status info, cd into one quickly, or run something like &lt;code&gt;npm install&lt;/code&gt; in the new directory after checkout. The raw git commands work, but they don't make worktrees feel like a real workflow.&lt;/p&gt;

&lt;p&gt;These aren't fundamental problems with worktrees. They're tooling gaps. That's why I built &lt;a href="https://github.com/morellodev/arbor" rel="noopener noreferrer"&gt;arbor&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  A better workflow with arbor
&lt;/h2&gt;

&lt;p&gt;Arbor is a CLI that manages git worktrees. It keeps them organized in a central directory (&lt;code&gt;~/.arbor/worktrees/&lt;/code&gt;) and handles the stuff that plain git doesn't.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone a repo (sets up a bare repo + default branch worktree)&lt;/span&gt;
arbor clone user/my-app

&lt;span class="c"&gt;# Create a worktree for a new feature&lt;/span&gt;
arbor add feat/login

&lt;span class="c"&gt;# Shell integration auto-cds you into the worktree&lt;/span&gt;
&lt;span class="c"&gt;# You're now in ~/.arbor/worktrees/my-app/feat-login&lt;/span&gt;

&lt;span class="c"&gt;# Need to review a PR? Open another worktree&lt;/span&gt;
arbor add fix/auth-bug

&lt;span class="c"&gt;# See all your worktrees with dirty/clean status&lt;/span&gt;
arbor status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Every worktree for &lt;code&gt;my-app&lt;/code&gt; lives under &lt;code&gt;~/.arbor/worktrees/my-app/&lt;/code&gt;. Branch slashes become dashes in directory names, so the filesystem stays tidy. When you're done with a branch:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;arbor &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; feat/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That removes the worktree and the local branch in one step.&lt;/p&gt;
&lt;h2&gt;
  
  
  What makes it stick
&lt;/h2&gt;

&lt;p&gt;I've been using worktrees for a while, but I kept falling off because of the friction. A few things in arbor made the difference for me.&lt;/p&gt;

&lt;p&gt;Shell integration. &lt;code&gt;arbor init&lt;/code&gt; sets up a wrapper so that &lt;code&gt;arbor add&lt;/code&gt; and &lt;code&gt;arbor switch&lt;/code&gt; automatically cd you into the worktree directory. Without it you create the worktree and then have to &lt;code&gt;cd&lt;/code&gt; into it yourself every single time, which gets old fast.&lt;/p&gt;

&lt;p&gt;Post-create hooks. You can add an &lt;code&gt;.arbor.toml&lt;/code&gt; to your repo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[hooks]&lt;/span&gt;
&lt;span class="py"&gt;post_create&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"npm install"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Every new worktree gets its dependencies installed automatically. You can chain commands too:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[hooks]&lt;/span&gt;
&lt;span class="py"&gt;post_create&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"npm install"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"cp .env.example .env"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And &lt;code&gt;arbor status --all&lt;/code&gt; shows the state of every worktree across all your repos, which is nice for a quick scan before you call it a day.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where I use them most
&lt;/h2&gt;

&lt;p&gt;PR reviews. &lt;code&gt;arbor add&lt;/code&gt; the branch, review it in a separate editor window, remove it when done. My own work is untouched.&lt;/p&gt;

&lt;p&gt;Long test suites. Tests running on one branch, coding on another. No waiting around.&lt;/p&gt;

&lt;p&gt;Hotfixes. &lt;code&gt;arbor add hotfix/critical&lt;/code&gt;, fix it, push it, remove it. Back to what I was doing.&lt;/p&gt;

&lt;p&gt;Comparing behavior. Two worktrees open side by side, one on &lt;code&gt;main&lt;/code&gt; and one on my feature branch. Way easier than switching back and forth.&lt;/p&gt;

&lt;p&gt;Big migrations. Upgrading a framework to a new major version in a worktree while the rest of the team keeps shipping from &lt;code&gt;main&lt;/code&gt;. No half-broken build blocking anyone.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Arbor is open source, written in Rust. Install with Homebrew:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;morellodev/tap/arbor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Or grab a binary from the &lt;a href="https://github.com/morellodev/arbor/releases/latest" rel="noopener noreferrer"&gt;releases page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;arbor init&lt;/code&gt; after installing to set up shell integration. Takes about 30 seconds.&lt;/p&gt;

&lt;p&gt;If you've never tried worktrees, give them a shot. And if you have but gave up because of the directory mess, this might be worth another look.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/morellodev" rel="noopener noreferrer"&gt;
        morellodev
      &lt;/a&gt; / &lt;a href="https://github.com/morellodev/arbor" rel="noopener noreferrer"&gt;
        arbor
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A friendly CLI for managing git worktrees
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🌳 arbor&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/morellodev/arbor/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/morellodev/arbor/actions/workflows/ci.yml/badge.svg" alt="Test &amp;amp; Lint"&gt;&lt;/a&gt;
&lt;a href="https://github.com/morellodev/arbor/releases/latest" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f3acaace43b060d086262a3945d6baf0769e50f291ecbf02c4537585761980ba/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6d6f72656c6c6f6465762f6172626f72" alt="GitHub Release"&gt;&lt;/a&gt;
&lt;a href="https://github.com/morellodev/arbor/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A CLI for managing git worktrees. It keeps all your worktrees under &lt;code&gt;~/.arbor/worktrees&lt;/code&gt; so you can switch between branches without stashing or losing context.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/morellodev/arbor/demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fmorellodev%2Farbor%2Fdemo.gif" alt="demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why arbor?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Git worktrees are great: multiple branches checked out at once, no stashing, no half-finished commits. The problem is that &lt;code&gt;git worktree add&lt;/code&gt; makes you pick a directory every time, and you end up with worktrees scattered everywhere.&lt;/p&gt;
&lt;p&gt;Arbor puts them all in one place. &lt;code&gt;arbor add feat/login&lt;/code&gt; creates the worktree, and with shell integration it &lt;code&gt;cd&lt;/code&gt;s you into it too. &lt;code&gt;arbor rm feat/login&lt;/code&gt; cleans it up.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Who is this for?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;If you review PRs while working on your own feature, juggle hotfixes alongside long-running branches, or run tests in one worktree while coding in another — arbor keeps everything organized.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Homebrew (macOS and Linux)&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;brew install morellodev/tap/arbor&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Pre-built binaries (macOS, Linux, Windows)&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Download the latest binary for your platform from…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/morellodev/arbor" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




</description>
      <category>git</category>
      <category>cli</category>
      <category>productivity</category>
      <category>rust</category>
    </item>
    <item>
      <title>Recreating History: Building a Windows 98 Disk Defrag Simulator with Modern Web Tech</title>
      <dc:creator>Dennis Morello</dc:creator>
      <pubDate>Sun, 14 Jul 2024 09:41:54 +0000</pubDate>
      <link>https://forem.com/morellodev/recreating-history-building-a-windows-98-disk-defrag-simulator-with-modern-web-tech-34bc</link>
      <guid>https://forem.com/morellodev/recreating-history-building-a-windows-98-disk-defrag-simulator-with-modern-web-tech-34bc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysehm1enkypm8d71gnxj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysehm1enkypm8d71gnxj.gif" alt="Defragmenting a disk in Windows 98 Disk Defrag Simulator" width="900" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hey fellow devs! I'm Dennis Morello, a Senior Frontend Engineer with a passion for both cutting-edge web technologies and retro computing. I'm excited to share my latest project that combines these interests: a faithful recreation of the Windows 98 Disk Defragmenter, built entirely for the web.&lt;/p&gt;

&lt;p&gt;Check it out: &lt;a href="https://defrag98.com" rel="noopener noreferrer"&gt;defrag98.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Update 19 Jul 2024: We're on Product Hunt! 🚀
&lt;/h2&gt;

&lt;p&gt;Great news, everyone! The Windows 98 Disk Defragmenter Simulator is now &lt;a href="https://www.producthunt.com/posts/windows-98-disk-defrag-simulator" rel="noopener noreferrer"&gt;live on Product Hunt&lt;/a&gt;. This is an exciting milestone for the project, and I'm thrilled to share it with a wider audience of tech enthusiasts and nostalgia lovers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.producthunt.com/posts/windows-98-disk-defrag-simulator?embed=true&amp;amp;utm_source=badge-featured&amp;amp;utm_medium=badge&amp;amp;utm_souce=badge-windows-98-disk-defrag-simulator" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fapi.producthunt.com%2Fwidgets%2Fembed-image%2Fv1%2Ffeatured.svg%3Fpost_id%3D472182%26theme%3Dlight" alt="Windows 98 Disk Defrag Simulator - Relive the 90s: Windows 98 Defrag Simulator Nostalgia | Product Hunt" width="250" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Update 14 Jul 2024: Featured on The Verge and Hacker News!
&lt;/h2&gt;

&lt;p&gt;The project has been featured on &lt;a href="https://news.ycombinator.com/item?id=40962195" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt; and &lt;a href="https://www.theverge.com/2024/7/14/24198206/take-a-moment-to-reflect" rel="noopener noreferrer"&gt;The Verge&lt;/a&gt;! Thank you to everyone who has tried it out and shared their love for this blast from the past.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech Stack
&lt;/h2&gt;

&lt;p&gt;For this project, I leveraged some of the most powerful tools in modern web development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt;: For building the UI components&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next.js&lt;/strong&gt;: To optimize performance and SEO&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zustand&lt;/strong&gt;: To manage the state of the app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TailwindCSS&lt;/strong&gt;: To style the app, along with &lt;a href="https://jdan.github.io/98.css" rel="noopener noreferrer"&gt;98.css&lt;/a&gt; for bringing in the Windows 98 aesthetic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Radix UI Primitives&lt;/strong&gt;: For accessible interactive components like sliders and modals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vercel&lt;/strong&gt;: The hosting platform for the app&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Challenges and Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Recreating the Defragmentation Algorithm
&lt;/h3&gt;

&lt;p&gt;One of the biggest challenges was implementing a defragmentation algorithm that felt authentic. I created a custom algorithm that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Randomly selects clusters to process&lt;/li&gt;
&lt;li&gt;Simulates file movements across the disk&lt;/li&gt;
&lt;li&gt;Adjusts processing speed based on the selected virtual drive&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Pixel-Perfect UI Recreation
&lt;/h3&gt;

&lt;p&gt;Achieving the exact look and feel of Windows 98 required meticulous attention to detail. I used a combination of 98.css and TailwindCSS to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Match colors precisely&lt;/li&gt;
&lt;li&gt;Recreate the characteristic 'chunky' borders&lt;/li&gt;
&lt;li&gt;Implement the classic Windows 98 typography&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Simulating Hard Drive Sounds
&lt;/h3&gt;

&lt;p&gt;To add an extra layer of nostalgia, I implemented realistic hard drive sounds. This involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recording and editing authentic HDD sounds&lt;/li&gt;
&lt;li&gt;Leveraging the Web Audio API for precise playback control&lt;/li&gt;
&lt;li&gt;Synchronizing sound effects with the visual defragmentation process&lt;/li&gt;
&lt;li&gt;Adapting the HDD sounds to the chosen drive speed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;This project was a fantastic opportunity to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deep dive into the intricacies of writing a custom defrag algorithm, and find a balance between performance and simulation accuracy&lt;/li&gt;
&lt;li&gt;Explore the challenges of accurately simulating legacy software&lt;/li&gt;
&lt;li&gt;Push the boundaries of what's possible in browser-based applications&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This is a project I started just for fun, but I'm excited to see where it goes. I'm looking forward to continuing to improve the app, and adding more features as feedbacks from users come in.&lt;/p&gt;

&lt;p&gt;I'd love to hear your thoughts, suggestions, or questions about this project. Have you worked on similar retro tech simulations? What challenges did you face?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>nextjs</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>5 Things You Might Not Know About JavaScript</title>
      <dc:creator>Dennis Morello</dc:creator>
      <pubDate>Thu, 08 Jun 2023 06:50:30 +0000</pubDate>
      <link>https://forem.com/morellodev/5-things-you-might-not-know-about-javascript-5dck</link>
      <guid>https://forem.com/morellodev/5-things-you-might-not-know-about-javascript-5dck</guid>
      <description>&lt;p&gt;JavaScript is a programming language that has been around for over 20 years. It's used in many different ways, but what are some things you might not know about it? In this blog post, we'll explore 5 things you might not know about JavaScript.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Original post at &lt;a href="https://morello.dev/articles/five-things-you-might-not-know-about-javascript" rel="noopener noreferrer"&gt;https://morello.dev/articles/five-things-you-might-not-know-about-javascript&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;JavaScript has undoubtedly become one of the most essential programming languages in the world of web development. As the backbone of interactive web pages, it enables developers to create dynamic and engaging user experiences. You might already be familiar with the basics of JavaScript, but there are numerous lesser-known aspects and hidden gems within the language that can enhance your coding skills and expand your understanding.&lt;/p&gt;

&lt;p&gt;In this blog post, we'll delve into 5 intriguing things about JavaScript that you might not be aware of. Whether you're ready to impress your colleagues with newfound JavaScript knowledge or simply eager to enhance your own programming prowess, this blog post is for you. Let's dive in and uncover the hidden gems that await us in the vast world of JavaScript!&lt;/p&gt;

&lt;h2&gt;
  
  
  1 - "JavaScript" is trademarked by Oracle
&lt;/h2&gt;

&lt;p&gt;The name "JavaScript" is a &lt;a href="https://tsdr.uspto.gov/#caseNumber=75026640&amp;amp;caseType=SERIAL_NO&amp;amp;searchType=statusSearch" rel="noopener noreferrer"&gt;trademark of Oracle Corporation&lt;/a&gt; in the United States. The trademark was originally owned by Netscape Communications Corporation, which created the language in 1995. In 1996, Netscape transferred the trademark to Sun Microsystems, which was acquired by Oracle in 2010.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A trademark is a legal protection that grants exclusive rights to use a particular word, phrase, symbol, or design to identify and distinguish a product or service.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a trademark holder, Oracle has the authority to control the usage of the term "JavaScript" within the United States. This means that other entities must seek permission from Oracle or adhere to specific guidelines if they wish to use the term in a way that may be covered by the trademark. Unauthorized use of a trademarked term can lead to legal repercussions.&lt;/p&gt;

&lt;p&gt;It is important to note that while the term "JavaScript" is trademarked by Oracle in the United States, the programming language itself is an open standard governed by the ECMAScript specification. This means that the language can still be used and implemented by developers and organizations globally, regardless of the trademark ownership.&lt;/p&gt;

&lt;p&gt;In 2022, Node.js and Deno creator &lt;a href="https://tinyclouds.org" rel="noopener noreferrer"&gt;Ryan Dahl&lt;/a&gt; wrote an open letter titled &lt;a href="https://tinyclouds.org/trademark" rel="noopener noreferrer"&gt;Dear Oracle, Please Release the JavaScript Trademark&lt;/a&gt;, where he urges Oracle to release JavaScript trademark.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - JavaScript and ECMAScript are not the same thing
&lt;/h2&gt;

&lt;p&gt;JavaScript is often referred to as &lt;em&gt;ECMAScript&lt;/em&gt;, but the two terms are not interchangeable. JavaScript is a programming language, while ECMAScript is a standardized specification that defines the syntax, semantics, and features of the JavaScript language. It provides a standardized framework for implementing JavaScript across different platforms and browsers.&lt;/p&gt;

&lt;p&gt;ECMAScript is maintained by &lt;a href="https://www.ecma-international.org" rel="noopener noreferrer"&gt;Ecma International&lt;/a&gt;, an industry association, and undergoes regular updates to introduce new features and enhancements.&lt;/p&gt;

&lt;p&gt;It is important to note that different versions of JavaScript correspond to different editions of the ECMAScript specification. For example, ECMAScript 5 (ES5) introduced significant improvements and features to the JavaScript language, while ECMAScript 6 (ES6) brought about even more significant changes, such as arrow functions, classes, and modules.&lt;/p&gt;

&lt;p&gt;In summary, JavaScript is the widely used programming language that follows the ECMAScript specification. ECMAScript provides the standardization and guidelines for implementing JavaScript across platforms, ensuring compatibility and allowing developers to write code that can be executed consistently.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 - JavaScript is a dynamically typed language
&lt;/h2&gt;

&lt;p&gt;As in every programming language, in JavaScript variables and values have types associated with them. Although JavaScript is often referred to as a &lt;em&gt;dynamically typed&lt;/em&gt; language, meaning that variables can hold values of any type, it does have a type system that determines how values can be used and manipulated.&lt;/p&gt;

&lt;p&gt;JavaScript employs a loose type system, where type coercion can occur implicitly, allowing for flexibility in operations between different types. For example, the &lt;code&gt;+&lt;/code&gt; operator can be used to add numbers or concatenate strings, but also to cast a value to a number.&lt;/p&gt;

&lt;p&gt;There is also an operator called &lt;code&gt;typeof&lt;/code&gt; that can be used to determine the type of a value at a given point in time. It returns a string representing the type of the operand.&lt;/p&gt;

&lt;h2&gt;
  
  
  4 - JavaScript has seven primitive types
&lt;/h2&gt;

&lt;p&gt;As of &lt;a href="https://262.ecma-international.org/11.0" rel="noopener noreferrer"&gt;ECMAScript 2020&lt;/a&gt; release, JavaScript has seven primitive types, which are the building blocks of all JavaScript values:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Boolean&lt;/strong&gt;: Represents a logical value of either &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Null&lt;/strong&gt;: Represents the intentional absence of any object value. It is a primitive type, but its sole value is &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Undefined&lt;/strong&gt;: Represents a variable that has been declared but has not been assigned a value. If a variable is declared but not assigned a value, it is automatically assigned the value of &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number&lt;/strong&gt;: Represents numeric values, including integers and floating-point numbers. JavaScript uses the double-precision 64-bit binary format (&lt;a href="https://en.wikipedia.org/wiki/IEEE_754" rel="noopener noreferrer"&gt;IEEE 754&lt;/a&gt;) to represent numbers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BigInt&lt;/strong&gt;: Introduced in ECMAScript 2020, BigInt is a primitive type that provides a way to represent arbitrarily large integers. It allows developers to perform operations on numbers beyond the limits of the Number type.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;String&lt;/strong&gt;: Represents a sequence of characters enclosed in single quotes (''), double quotes ("") or backticks (``). Strings are used to store and manipulate textual data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Symbol&lt;/strong&gt;: Introduced in &lt;a href="https://262.ecma-international.org/6.0" rel="noopener noreferrer"&gt;ECMAScript 2015&lt;/a&gt;, &lt;code&gt;Symbol&lt;/code&gt; is a primitive type that represents a unique identifier. Symbols are often used as keys in objects to avoid name collisions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These primitive types in JavaScript are &lt;em&gt;immutable&lt;/em&gt;, meaning their values cannot be changed once created. They are distinct from objects, which are composite data types that can store multiple values and have methods and properties associated with them.&lt;/p&gt;

&lt;p&gt;Another property of primitive types in JavaScript is that they are passed &lt;em&gt;by value&lt;/em&gt;. This means that when a primitive value is assigned to a variable or passed as an argument to a function, a copy of the value is created and stored in the variable or parameter, and any changes made to the variable or parameter will not affect the original value.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 - JavaScript is a "compiled" language
&lt;/h2&gt;

&lt;p&gt;In the context of JavaScript, the term &lt;em&gt;compiled&lt;/em&gt; can be misleading. Unlike languages such as C++ or Rust, where the source code is directly transformed into machine code before execution, JavaScript goes through a different process. When a JavaScript program is executed, it is first passed through a &lt;a href="https://en.wikipedia.org/wiki/Just-in-time_compilation" rel="noopener noreferrer"&gt;just-in-time (JIT) compiler&lt;/a&gt; built into the JavaScript engine.&lt;/p&gt;

&lt;p&gt;During the execution, the &lt;a href="https://en.wikipedia.org/wiki/JavaScript_engine" rel="noopener noreferrer"&gt;JavaScript engine&lt;/a&gt; performs several optimizations, including parsing the source code, optimizing the code based on various heuristics, and generating machine code or bytecode for efficient execution. This dynamic compilation process, performed by the JavaScript engine at runtime, helps improve the performance of JavaScript programs.&lt;/p&gt;

&lt;p&gt;It is worth noting that the compilation process in JavaScript is different from the traditional pre-compilation step found in languages like C or C++. In JavaScript, there is no separate compilation step that generates an executable file beforehand. Instead, the compilation happens as part of the runtime execution.&lt;/p&gt;

&lt;p&gt;Overall, while JavaScript can be considered a compiled language in the sense that it undergoes compilation during runtime, it is more accurate to describe it as an interpreted language with a just-in-time compilation process.&lt;/p&gt;

&lt;p&gt;If you want to go deeper, &lt;a href="https://me.getify.com" rel="noopener noreferrer"&gt;Kyle Simpson&lt;/a&gt; explores this topic in detail in his book &lt;a href="https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/get-started/ch1.md#whats-in-an-interpretation" rel="noopener noreferrer"&gt;You Don't Know JS Yet&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;JavaScript never ceases to surprise and fascinate developers with its hidden depths and lesser-known features. In this blog post, we explored five intriguing aspects of JavaScript that you might not have been aware of, expanding your understanding of this versatile language.&lt;/p&gt;

&lt;p&gt;As you continue your journey with JavaScript, remember that there is always more to explore and learn. Embrace the ever-evolving nature of this dynamic language, and continue to discover new facets that will enhance your development skills.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>learning</category>
      <category>programming</category>
    </item>
    <item>
      <title>React Awesome Reveal v3 Beta</title>
      <dc:creator>Dennis Morello</dc:creator>
      <pubDate>Sun, 02 Aug 2020 21:43:21 +0000</pubDate>
      <link>https://forem.com/morellodev/react-awesome-reveal-v3-beta-459m</link>
      <guid>https://forem.com/morellodev/react-awesome-reveal-v3-beta-459m</guid>
      <description>&lt;p&gt;React Awesome Reveal v3 using Emotion to provide animations is now on beta 🎉 Check it out by adding react-awesome-reveal@beta to your React project.&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>react-awesome-reveal v2.4.0 released!</title>
      <dc:creator>Dennis Morello</dc:creator>
      <pubDate>Sat, 18 Jan 2020 11:12:32 +0000</pubDate>
      <link>https://forem.com/morellodev/react-awesome-reveal-v2-4-0-released-4ghj</link>
      <guid>https://forem.com/morellodev/react-awesome-reveal-v2-4-0-released-4ghj</guid>
      <description>&lt;p&gt;A new version of &lt;a href="https://www.npmjs.com/package/react-awesome-reveal/v/2.4.0" rel="noopener noreferrer"&gt;react-awesome-reveal&lt;/a&gt; has just been released, featuring a &lt;code&gt;reverse&lt;/code&gt; option that... reverses the animation direction 👻 It is useful for making elements visible and invisible in a controlled way (form error indicators, badges, notifications and so on)!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Add data-test-id attributes to React apps</title>
      <dc:creator>Dennis Morello</dc:creator>
      <pubDate>Fri, 03 Jan 2020 22:10:11 +0000</pubDate>
      <link>https://forem.com/morellodev/add-data-test-id-attributes-to-react-apps-1hfj</link>
      <guid>https://forem.com/morellodev/add-data-test-id-attributes-to-react-apps-1hfj</guid>
      <description>&lt;p&gt;Meet &lt;strong&gt;react-test-attributes&lt;/strong&gt;, my new library for React apps to add custom &lt;code&gt;data-*&lt;/code&gt; attributes to DOM elements. Use it for your E2E tests!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/react-test-attributes" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/react-test-attributes&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>testing</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>React Awesome Reveal v2 Released</title>
      <dc:creator>Dennis Morello</dc:creator>
      <pubDate>Sat, 30 Nov 2019 21:57:18 +0000</pubDate>
      <link>https://forem.com/morellodev/react-awesome-reveal-v2-released-2m80</link>
      <guid>https://forem.com/morellodev/react-awesome-reveal-v2-released-2m80</guid>
      <description>&lt;p&gt;React Awesome Reveal has just received a major update featuring zero external dependencies and a cleaner API 🎉 Check it out at &lt;a href="https://github.com/dennismorello/react-awesome-reveal" rel="noopener noreferrer"&gt;github.com/dennismorello/react-awesome-reveal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react-awesome-reveal.morello.dev" rel="noopener noreferrer"&gt;Demo site&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>React Awesome Reveal</title>
      <dc:creator>Dennis Morello</dc:creator>
      <pubDate>Tue, 26 Nov 2019 18:26:32 +0000</pubDate>
      <link>https://forem.com/morellodev/react-awesome-reveal-1khh</link>
      <guid>https://forem.com/morellodev/react-awesome-reveal-1khh</guid>
      <description>&lt;p&gt;Hi all, I am writing &lt;a href="https://github.com/dennismorello/react-awesome-reveal" rel="noopener noreferrer"&gt;react-awesome-reveal&lt;/a&gt;, a React library to animate elements when they appear in the browser viewport. It uses the Intersection Observer API and CSS Animations to be buttery smooth 🚀&lt;/p&gt;

&lt;p&gt;Let me know what you think!&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>css</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
