<?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: Rodrigo Oler</title>
    <description>The latest articles on Forem by Rodrigo Oler (@oler).</description>
    <link>https://forem.com/oler</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%2F110289%2F37ddc906-d68a-4c90-8ce2-4fb4551e064a.png</url>
      <title>Forem: Rodrigo Oler</title>
      <link>https://forem.com/oler</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/oler"/>
    <language>en</language>
    <item>
      <title>How to Detect and Remove the Axios Malware from Your Project</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Tue, 31 Mar 2026 13:15:48 +0000</pubDate>
      <link>https://forem.com/oler/how-to-detect-and-remove-the-axios-malware-from-your-project-acf</link>
      <guid>https://forem.com/oler/how-to-detect-and-remove-the-axios-malware-from-your-project-acf</guid>
      <description>&lt;p&gt;If your project may have installed the malicious Axios releases, treat it like a real incident.&lt;/p&gt;

&lt;p&gt;The fastest path is to verify exposure, contain execution, and rotate anything sensitive that may have been available during the install window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with verification
&lt;/h2&gt;

&lt;p&gt;Use the tools you already have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;ls &lt;/span&gt;axios
npm &lt;span class="nb"&gt;ls &lt;/span&gt;plain-crypto-js
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"axios@1.14.1&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;axios@0.30.4&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;plain-crypto-js@4.2.1"&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using pnpm or yarn, inspect the corresponding lockfile and workspace tree as well.&lt;/p&gt;

&lt;p&gt;The goal is not just to know whether Axios appears in the repository.&lt;br&gt;
The goal is to know whether the malicious versions were resolved and installed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Treat the install window as suspicious
&lt;/h2&gt;

&lt;p&gt;The public writeups from Aikido Security, Socket, Semgrep, and StepSecurity all point to the same response pattern: assume exposure until you have evidence otherwise.&lt;/p&gt;

&lt;p&gt;Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;installs that ran &lt;code&gt;postinstall&lt;/code&gt; or other scripts&lt;/li&gt;
&lt;li&gt;temporary files created during package installation&lt;/li&gt;
&lt;li&gt;background child processes spawned by npm&lt;/li&gt;
&lt;li&gt;outbound traffic during dependency install windows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have EDR or SIEM visibility, focus on process lineage and network logs first. That is where a lot of the evidence will show up.&lt;/p&gt;
&lt;h2&gt;
  
  
  Contain first
&lt;/h2&gt;

&lt;p&gt;Do not wait for a perfect forensic picture before you act.&lt;/p&gt;

&lt;p&gt;Start containment with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm ci &lt;span class="nt"&gt;--ignore-scripts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then rebuild from a clean lockfile and package manifest.&lt;/p&gt;

&lt;p&gt;If the affected package executed on a machine or in CI where secrets were available, rotate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;npm tokens&lt;/li&gt;
&lt;li&gt;cloud credentials&lt;/li&gt;
&lt;li&gt;CI secrets&lt;/li&gt;
&lt;li&gt;signing keys&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are unsure whether a secret was exposed, treat it as exposed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check on endpoints
&lt;/h2&gt;

&lt;p&gt;Search for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unusual &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;python3&lt;/code&gt;, or shell execution during dependency install&lt;/li&gt;
&lt;li&gt;files written to &lt;code&gt;/tmp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;unexpected child processes from &lt;code&gt;npm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;connections to attacker-controlled infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you think an affected machine executed the package, assume the install path was a compromise path until proven otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to keep in place after cleanup
&lt;/h2&gt;

&lt;p&gt;Once you contain the incident, keep a few defensive defaults:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pin dependencies more aggressively&lt;/li&gt;
&lt;li&gt;review lockfile changes in PRs&lt;/li&gt;
&lt;li&gt;keep &lt;code&gt;npm ci --ignore-scripts&lt;/code&gt; in CI&lt;/li&gt;
&lt;li&gt;restrict outbound access from build jobs where possible&lt;/li&gt;
&lt;li&gt;document the response path for future dependency compromises&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes the next incident much easier to handle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful tools
&lt;/h2&gt;

&lt;p&gt;The tools most often mentioned in the incident response guidance are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Snyk&lt;/li&gt;
&lt;li&gt;Socket&lt;/li&gt;
&lt;li&gt;Semgrep&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those tools do not replace response work, but they help you move faster.&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://oler.pages.dev/blog/how-to-detect-and-remove-the-axios-malware-from-your-project" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>npm</category>
      <category>devops</category>
      <category>incidentresponse</category>
    </item>
    <item>
      <title>How to Protect JavaScript Projects Against Supply Chain Attacks</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Tue, 31 Mar 2026 13:15:02 +0000</pubDate>
      <link>https://forem.com/oler/how-to-protect-javascript-projects-against-supply-chain-attacks-52o0</link>
      <guid>https://forem.com/oler/how-to-protect-javascript-projects-against-supply-chain-attacks-52o0</guid>
      <description>&lt;p&gt;The Axios incident is a useful reminder that npm risk is not abstract.&lt;/p&gt;

&lt;p&gt;A practical defense model for JavaScript projects starts with a few boring but effective controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  The baseline
&lt;/h2&gt;

&lt;p&gt;Use these defaults:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pin versions and keep lockfiles committed&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;npm ci --ignore-scripts&lt;/code&gt; in CI&lt;/li&gt;
&lt;li&gt;review dependency changes like code changes&lt;/li&gt;
&lt;li&gt;use short-lived credentials where possible&lt;/li&gt;
&lt;li&gt;rotate secrets after suspicious installs&lt;/li&gt;
&lt;li&gt;separate build credentials from runtime credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That will not eliminate supply chain risk, but it removes a lot of avoidable exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;The main mistake teams make is assuming supply-chain risk is just a vulnerability scanning problem.&lt;/p&gt;

&lt;p&gt;It is broader than that.&lt;/p&gt;

&lt;p&gt;It is a process problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;install policy&lt;/li&gt;
&lt;li&gt;dependency review&lt;/li&gt;
&lt;li&gt;secret scope&lt;/li&gt;
&lt;li&gt;CI isolation&lt;/li&gt;
&lt;li&gt;incident response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If those pieces do not work together, a malicious package has a much easier time moving through your system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to put in CI
&lt;/h2&gt;

&lt;p&gt;At minimum, I would recommend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm ci &lt;span class="nt"&gt;--ignore-scripts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add policy around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lockfile diffs&lt;/li&gt;
&lt;li&gt;minimum release age rules for critical packages&lt;/li&gt;
&lt;li&gt;package allowlists for sensitive environments&lt;/li&gt;
&lt;li&gt;alerts for unexpected dependency ownership changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools like Renovate and Dependabot help, but only if you configure them with policy instead of treating them as passive update bots.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Axios case is useful
&lt;/h2&gt;

&lt;p&gt;The Axios incident is not interesting because it was unique.&lt;br&gt;
It is interesting because it was plausible.&lt;/p&gt;

&lt;p&gt;The attack worked because it used the same trust paths teams already rely on every day: a popular package, a maintainer account, and an install-time hook.&lt;/p&gt;

&lt;p&gt;That is why the best defenses are often boring, repeatable controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical checklist
&lt;/h2&gt;

&lt;p&gt;Before you ship, check that you can answer these questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who reviews dependency changes?&lt;/li&gt;
&lt;li&gt;Which builds can execute install scripts?&lt;/li&gt;
&lt;li&gt;Which secrets are present in CI?&lt;/li&gt;
&lt;li&gt;What happens if a package becomes compromised tomorrow?&lt;/li&gt;
&lt;li&gt;How fast can you rotate credentials if that happens?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If those answers are fuzzy, that is where to start.&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://oler.pages.dev/blog/how-to-protect-javascript-projects-against-supply-chain-attacks" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>javascript</category>
      <category>npm</category>
      <category>devops</category>
    </item>
    <item>
      <title>Axios Supply Chain Attack: How the 2026 npm Compromise Happened</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Tue, 31 Mar 2026 13:15:01 +0000</pubDate>
      <link>https://forem.com/oler/axios-supply-chain-attack-how-the-2026-npm-compromise-happened-4d7j</link>
      <guid>https://forem.com/oler/axios-supply-chain-attack-how-the-2026-npm-compromise-happened-4d7j</guid>
      <description>&lt;p&gt;Axios was compromised on March 31, 2026 through a supply-chain attack that turned a trusted npm dependency into a cross-platform malware delivery vector.&lt;/p&gt;

&lt;p&gt;What makes this incident worth studying is not just the package name. It is the way the attack combined account compromise, malicious package publication, install-time execution, and platform-specific behavior.&lt;/p&gt;

&lt;p&gt;The public reporting from StepSecurity, The Hacker News, and Snyk points to malicious releases &lt;code&gt;axios@1.14.1&lt;/code&gt; and &lt;code&gt;axios@0.30.4&lt;/code&gt;, plus a staged package named &lt;code&gt;plain-crypto-js@4.2.1&lt;/code&gt;. The payload used &lt;code&gt;postinstall&lt;/code&gt;, then branched by operating system and reached out to attacker infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;The attacker did not need to make Axios look radically different.&lt;br&gt;
They only needed the package to behave differently during installation.&lt;/p&gt;

&lt;p&gt;That is what makes the incident dangerous:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it happened inside a trusted package&lt;/li&gt;
&lt;li&gt;it executed during install&lt;/li&gt;
&lt;li&gt;it behaved differently on macOS, Windows, and Linux&lt;/li&gt;
&lt;li&gt;it used a staged dependency to make the chain less obvious&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Many teams still think about package compromise as a rare edge case.&lt;br&gt;
The Axios incident shows the opposite. A popular package can become a malware delivery vehicle without changing its role in the codebase or its reputation in the ecosystem.&lt;/p&gt;

&lt;p&gt;That means dependency trust is not stable. It needs to be managed.&lt;/p&gt;
&lt;h2&gt;
  
  
  What defenders should focus on
&lt;/h2&gt;

&lt;p&gt;The practical lessons are straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;treat install scripts as a real risk surface&lt;/li&gt;
&lt;li&gt;inspect lockfiles, not just manifests&lt;/li&gt;
&lt;li&gt;run CI with &lt;code&gt;npm ci --ignore-scripts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;rotate secrets after suspicious installs&lt;/li&gt;
&lt;li&gt;look for temporary files and unusual outbound traffic during dependency installation&lt;/li&gt;
&lt;li&gt;keep runtime and CI environments separated as much as possible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a package ran in an environment with credentials, assume those credentials may have been exposed until proven otherwise.&lt;/p&gt;
&lt;h2&gt;
  
  
  A simple mental model
&lt;/h2&gt;

&lt;p&gt;When you review incidents like this, think in layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;how the package was compromised&lt;/li&gt;
&lt;li&gt;how the payload executed&lt;/li&gt;
&lt;li&gt;how the attacker gained persistence or second-stage execution&lt;/li&gt;
&lt;li&gt;what data or credentials were present at install time&lt;/li&gt;
&lt;li&gt;what the team can do differently in CI and developer machines&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That model keeps the response practical instead of emotional.&lt;/p&gt;
&lt;h2&gt;
  
  
  What to check first
&lt;/h2&gt;

&lt;p&gt;If you suspect exposure, start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;ls &lt;/span&gt;axios
npm &lt;span class="nb"&gt;ls &lt;/span&gt;plain-crypto-js
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"axios@1.14.1&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;axios@0.30.4&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;plain-crypto-js@4.2.1"&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI logs for installs that ran scripts&lt;/li&gt;
&lt;li&gt;developer machines that used the affected lockfile&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/tmp&lt;/code&gt; or other writable paths for suspicious files&lt;/li&gt;
&lt;li&gt;outbound traffic during dependency installation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The real takeaway
&lt;/h2&gt;

&lt;p&gt;The important lesson is not just that Axios was compromised.&lt;br&gt;
It is that supply chain risk is now a normal part of JavaScript security work.&lt;/p&gt;

&lt;p&gt;If you build and ship JavaScript software, you need a response path for upstream trust failures before they happen.&lt;/p&gt;

&lt;p&gt;That includes install policy, secret rotation, dependency review, and incident response.&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://oler.pages.dev/blog/axios-compromised-how-the-2026-npm-supply-chain-attack-happened" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>npm</category>
      <category>supplychain</category>
      <category>axios</category>
    </item>
    <item>
      <title>Pyth Oracle: A Simple Way to Integrate Price Feeds with Bun and Elysia</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Tue, 31 Mar 2026 13:13:57 +0000</pubDate>
      <link>https://forem.com/oler/pyth-oracle-a-simple-way-to-integrate-price-feeds-with-bun-and-elysia-56lm</link>
      <guid>https://forem.com/oler/pyth-oracle-a-simple-way-to-integrate-price-feeds-with-bun-and-elysia-56lm</guid>
      <description>&lt;p&gt;If you need market data in a clean, modern stack, Pyth is one of the easiest oracle systems to work with.&lt;/p&gt;

&lt;p&gt;The reason is simple: Pyth gives you real-time price feeds, and its API surface is built for developers. For off-chain integration, Hermes exposes those updates through a web API. For on-chain use, Pyth provides the contract-side update flow you use to verify and read prices on the target chain.&lt;/p&gt;

&lt;p&gt;That makes Pyth useful in two different places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;as a price source for backend services&lt;/li&gt;
&lt;li&gt;as an oracle layer for smart contracts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a lot of teams, the off-chain side is where the fastest value appears first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Pyth feels easy to integrate
&lt;/h2&gt;

&lt;p&gt;Pyth is not trying to be a generic data platform. It is focused on market data, so the mental model stays simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choose the feed you want&lt;/li&gt;
&lt;li&gt;fetch the latest update&lt;/li&gt;
&lt;li&gt;expose it in your app&lt;/li&gt;
&lt;li&gt;use it where your product needs a trusted price&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pyth’s Hermes service is the cleanest way to start if you want REST access. It serves the latest price update data through an API, and the docs also show that Pyth has a broader API reference for on-chain and off-chain integrations.&lt;/p&gt;

&lt;p&gt;That is a good fit for teams that want to move quickly without wiring up a large data stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bun works well here
&lt;/h2&gt;

&lt;p&gt;Bun is a very natural fit for this kind of integration because it gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a fast runtime&lt;/li&gt;
&lt;li&gt;built-in &lt;code&gt;fetch&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;TypeScript support out of the box&lt;/li&gt;
&lt;li&gt;easy package management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, that means you can write a small service that fetches oracle data and exposes it through a REST endpoint without much ceremony.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Elysia makes the REST layer nicer
&lt;/h2&gt;

&lt;p&gt;Elysia is a strong match for Bun because it is built to be ergonomic, type-safe, and fast to wire up.&lt;/p&gt;

&lt;p&gt;For a tiny oracle service, that matters more than people think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;route definitions stay readable&lt;/li&gt;
&lt;li&gt;request validation is easy to add&lt;/li&gt;
&lt;li&gt;the code stays close to the actual API contract&lt;/li&gt;
&lt;li&gt;you can expose OpenAPI docs if you want the service to be self-describing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the kind of setup that stays pleasant even when the service grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal Bun + Elysia example
&lt;/h2&gt;

&lt;p&gt;Here is a simple REST wrapper around Hermes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Elysia&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;elysia&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Elysia&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/price/:feedId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="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="kd"&gt;set&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://hermes.pyth.network/v2/updates/price/latest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ids[]&lt;/span&gt;&lt;span class="dl"&gt;'&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;feedId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;502&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to fetch price feed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;feeds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nl"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nl"&gt;expo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nl"&gt;publish_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;feeds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Price feed not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;exponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publish_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;feedId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Pyth proxy running on http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pattern is straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the client calls your API&lt;/li&gt;
&lt;li&gt;your API calls Hermes&lt;/li&gt;
&lt;li&gt;your API returns a clean JSON shape to the rest of your system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is usually enough to get a production-friendly integration started.&lt;/p&gt;

&lt;h2&gt;
  
  
  When this pattern is useful
&lt;/h2&gt;

&lt;p&gt;This setup works especially well for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dashboards that need live asset prices&lt;/li&gt;
&lt;li&gt;trading tools&lt;/li&gt;
&lt;li&gt;liquidation monitors&lt;/li&gt;
&lt;li&gt;risk checks&lt;/li&gt;
&lt;li&gt;internal services that need a stable oracle adapter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is also a nice boundary if you do not want every frontend or service to know about oracle-specific details.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to keep in mind
&lt;/h2&gt;

&lt;p&gt;The biggest mistake is treating oracle data like plain public JSON.&lt;/p&gt;

&lt;p&gt;You still need to think about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;feed freshness&lt;/li&gt;
&lt;li&gt;precision and decimals&lt;/li&gt;
&lt;li&gt;fallback behavior&lt;/li&gt;
&lt;li&gt;stale data handling&lt;/li&gt;
&lt;li&gt;whether the value is meant for display, decisions, or on-chain settlement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the price is going into a smart contract, use the chain-side integration and follow the update flow from the docs.&lt;/p&gt;

&lt;p&gt;If the price is only for your app or backend, Hermes through Bun + Elysia is a very clean path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Pyth is easy to integrate because it keeps the problem focused: real market data, exposed through a developer-friendly API.&lt;/p&gt;

&lt;p&gt;With Bun and Elysia, you can turn that into a tiny REST service very quickly. That gives you a neat separation between price feeds, your backend logic, and whatever UI or smart contract consumes the data.&lt;/p&gt;

&lt;p&gt;For teams that want to move fast without making the oracle layer complicated, this is a very practical stack.&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://oler.pages.dev/blog/pyth-oracle-integration-with-bun-and-elysia" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>pyth</category>
      <category>oracle</category>
      <category>bunjs</category>
      <category>elysia</category>
    </item>
    <item>
      <title>Why Hono + Bun Is a Strong Default for New JavaScript Backends</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Tue, 31 Mar 2026 13:13:55 +0000</pubDate>
      <link>https://forem.com/oler/why-hono-bun-is-a-strong-default-for-new-javascript-backends-3gpl</link>
      <guid>https://forem.com/oler/why-hono-bun-is-a-strong-default-for-new-javascript-backends-3gpl</guid>
      <description>&lt;p&gt;If you are starting a new JavaScript backend today, Hono with Bun is one of the most sensible combinations you can pick.&lt;/p&gt;

&lt;p&gt;Not because it is trendy. Not because it is the smallest stack on paper. It is a strong default because it removes a lot of the usual friction: startup time, package-manager overhead, framework bloat, and runtime lock-in.&lt;/p&gt;

&lt;p&gt;That matters more on new projects than on old ones. Greenfield code has a rare advantage: you can choose a stack based on current tradeoffs instead of legacy constraints. Hono and Bun are worth a serious look because they optimize for exactly that moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Hono and Bun actually are
&lt;/h2&gt;

&lt;p&gt;Hono is a small web framework built on Web Standards. Its official docs describe it as fast, lightweight, and compatible with many JavaScript runtimes, including Bun, Node.js, Deno, Cloudflare Workers, Fastly, and others.&lt;/p&gt;

&lt;p&gt;Bun is an all-in-one JavaScript and TypeScript toolkit. It gives you a runtime, package manager, test runner, and bundler in a single executable. Its docs emphasize fast startup, built-in tooling, and Node.js compatibility.&lt;/p&gt;

&lt;p&gt;Together, they cover two different layers of the stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hono handles HTTP routing, middleware, and request handling.&lt;/li&gt;
&lt;li&gt;Bun handles the runtime, package installation, scripts, tests, and bundling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination reduces the number of tools you need to stitch together before you can ship something useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the performance comes from
&lt;/h2&gt;

&lt;p&gt;Performance is the main reason people reach for this stack, but it is worth being precise about what “fast” means here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hono is fast because it stays close to the platform
&lt;/h3&gt;

&lt;p&gt;Hono is designed around Web Standard APIs instead of inventing a large framework abstraction. That keeps the runtime surface area small and makes it easier to run the same app across multiple environments.&lt;/p&gt;

&lt;p&gt;Its docs also highlight a few performance-related choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;RegExpRouter&lt;/code&gt; is designed for very fast route matching.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hono/tiny&lt;/code&gt; is intentionally small, with a minimal footprint.&lt;/li&gt;
&lt;li&gt;The framework avoids unnecessary dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That does not magically make every app fast. It does mean the framework itself is less likely to become the bottleneck.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bun is fast because the toolchain is integrated
&lt;/h3&gt;

&lt;p&gt;Bun’s performance story is broader than the runtime alone. It is fast because the developer workflow is built into one tool.&lt;/p&gt;

&lt;p&gt;Instead of waiting on a separate package manager, test runner, and bundler, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;quick installs&lt;/li&gt;
&lt;li&gt;quick startup&lt;/li&gt;
&lt;li&gt;fast script execution&lt;/li&gt;
&lt;li&gt;built-in testing&lt;/li&gt;
&lt;li&gt;built-in bundling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bun’s docs describe it as a fast, all-in-one toolkit and note that it is powered by JavaScriptCore under the hood. That gives it a very different profile from the usual Node.js + external-tooling setup.&lt;/p&gt;

&lt;p&gt;The practical result is less time spent waiting on scaffolding, cold starts, dependency installs, and repetitive local workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  The real win is system-level speed
&lt;/h3&gt;

&lt;p&gt;The biggest mistake is thinking this stack is only about raw request throughput.&lt;/p&gt;

&lt;p&gt;In practice, the speed comes from the whole system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the framework is lean&lt;/li&gt;
&lt;li&gt;the runtime starts quickly&lt;/li&gt;
&lt;li&gt;the tooling is built in&lt;/li&gt;
&lt;li&gt;the app can stay portable across runtimes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination improves both local development and deployment-time behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who maintains them
&lt;/h2&gt;

&lt;p&gt;For a new project, maintainership matters almost as much as performance. Fast software with weak stewardship is a future problem.&lt;/p&gt;

&lt;p&gt;Hono is maintained by Yusuke Wada, with router work attributed in the project to Taku Amano and the wider Hono contributor community. The public repository shows Hono as a long-lived open source project with active contributors.&lt;/p&gt;

&lt;p&gt;Bun is maintained by the Oven team, via the &lt;code&gt;oven-sh/bun&lt;/code&gt; project, and it also has a large contributor base. That matters because Bun is not a side experiment anymore. It is a substantial, actively developed runtime and toolkit.&lt;/p&gt;

&lt;p&gt;The important part is not just that both projects are open source. It is that both are moving quickly while still being built around clear ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hono: standards-first, portable, small&lt;/li&gt;
&lt;li&gt;Bun: integrated, fast, low-friction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives them a healthier long-term shape than a lot of “fast” tools that rely on one narrow implementation trick.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is a good choice for new projects
&lt;/h2&gt;

&lt;p&gt;If you are starting from zero, Hono + Bun gives you a very clean baseline.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. You get a smaller decision surface
&lt;/h3&gt;

&lt;p&gt;New projects often waste time on framework debates that have nothing to do with the product.&lt;/p&gt;

&lt;p&gt;With this stack, you can move quickly without assembling a large architecture first. Hono gives you routing and middleware without excess ceremony. Bun gives you the surrounding tools without forcing a separate ecosystem of scripts and dependencies.&lt;/p&gt;

&lt;p&gt;That makes the first commit easier and the next ten commits less annoying.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. You stay closer to web standards
&lt;/h3&gt;

&lt;p&gt;Hono’s standards-based approach makes future migration easier. If you later need to move between Bun, Node.js, serverless edge platforms, or containerized services, the app code is less likely to need a rewrite.&lt;/p&gt;

&lt;p&gt;That portability is especially valuable for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;internal dashboards&lt;/li&gt;
&lt;li&gt;edge functions&lt;/li&gt;
&lt;li&gt;proxies and middleware services&lt;/li&gt;
&lt;li&gt;small backends that may grow over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, you are not just buying speed. You are buying optionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Bun reduces the cost of the boring parts
&lt;/h3&gt;

&lt;p&gt;Most projects are slowed down by boring work, not hard work.&lt;/p&gt;

&lt;p&gt;Package installs, test runs, local scripts, and build steps happen constantly. Bun makes those chores cheaper. That improves feedback loops for the whole team, which is where most productivity gains actually come from.&lt;/p&gt;

&lt;p&gt;For a new project, that is a strong advantage because you feel it immediately on day one.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The ecosystem fit is good for modern backends
&lt;/h3&gt;

&lt;p&gt;If your backend is mostly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON APIs&lt;/li&gt;
&lt;li&gt;auth flows&lt;/li&gt;
&lt;li&gt;CRUD endpoints&lt;/li&gt;
&lt;li&gt;edge-friendly logic&lt;/li&gt;
&lt;li&gt;small composition-heavy services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;then Hono is a natural fit. It has the ergonomics of a lightweight framework without locking you into a heavy abstraction layer.&lt;/p&gt;

&lt;p&gt;If your team also wants a modern local workflow, Bun fits that same philosophy well.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal example
&lt;/h2&gt;

&lt;p&gt;This is the kind of setup that shows why the stack feels so clean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Hono&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hono&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Hono&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello from Hono on Bun&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run code like this with very little setup, and that is exactly the point. For a new service, fewer moving parts usually means fewer ways for the project to become sluggish later.&lt;/p&gt;

&lt;h2&gt;
  
  
  When I would not pick it
&lt;/h2&gt;

&lt;p&gt;No stack is universally correct.&lt;/p&gt;

&lt;p&gt;I would hesitate if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the team needs maximum Node.js compatibility with very old packages&lt;/li&gt;
&lt;li&gt;the service depends on niche native modules&lt;/li&gt;
&lt;li&gt;the project is already deeply standardized on another runtime&lt;/li&gt;
&lt;li&gt;the organization prefers very conservative tooling over speed and portability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are valid reasons to stay with a more established stack.&lt;/p&gt;

&lt;p&gt;But if you are building something new and you want a fast, modern default, Hono + Bun is hard to ignore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Hono and Bun are a good pairing because they solve adjacent problems well.&lt;/p&gt;

&lt;p&gt;Hono gives you a small, standards-based framework that works across runtimes. Bun gives you a fast runtime and a single toolchain for installs, tests, builds, and scripts. The result is a stack that is simple to start, fast to iterate on, and flexible enough to survive early product changes.&lt;/p&gt;

&lt;p&gt;That is why I would seriously consider it for any new JavaScript backend, especially if the project needs to move quickly without creating a lot of long-term framework debt.&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://oler.pages.dev/blog/hono-with-bun-for-new-projects" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>hono</category>
      <category>bunjs</category>
      <category>javascript</category>
      <category>backend</category>
    </item>
    <item>
      <title>Why Daily Standups Are Becoming Useless in the AI Era</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Sat, 28 Mar 2026 22:00:14 +0000</pubDate>
      <link>https://forem.com/oler/why-daily-standups-are-becoming-useless-in-the-ai-era-iao</link>
      <guid>https://forem.com/oler/why-daily-standups-are-becoming-useless-in-the-ai-era-iao</guid>
      <description>&lt;p&gt;Daily standups were supposed to improve coordination.&lt;/p&gt;

&lt;p&gt;In practice, they often became a ritual that burns engineering time without giving much back. The old 15-minute promise sounds harmless, but in most real teams it becomes 30 minutes, 1 hour, or even 1 hour 30 minutes once the conversation starts and people wait their turn.&lt;/p&gt;

&lt;p&gt;Strictly speaking, "daily" is the cadence and "standup" is the ceremony. In practice, people just use "daily" as shorthand for the meeting itself.&lt;/p&gt;

&lt;p&gt;That is where the math gets ugly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it used to make sense
&lt;/h2&gt;

&lt;p&gt;Standups were useful when teams had poor visibility and weak async tooling. They helped surface blockers, expose dependencies, and give managers a quick snapshot of progress.&lt;/p&gt;

&lt;p&gt;The problem is that many companies kept the ceremony long after the reason for it weakened.&lt;/p&gt;

&lt;p&gt;Today, engineers already have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ticket boards&lt;/li&gt;
&lt;li&gt;pull request summaries&lt;/li&gt;
&lt;li&gt;commit history&lt;/li&gt;
&lt;li&gt;Slack updates&lt;/li&gt;
&lt;li&gt;AI-generated status recaps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the status already exists in the system of record, forcing the whole team into a synchronous update ritual is usually redundant.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real cost
&lt;/h2&gt;

&lt;p&gt;The meeting itself is not the full cost. The expensive part is the context switching before and after it.&lt;/p&gt;

&lt;p&gt;Let’s make the assumptions explicit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 workdays per week&lt;/li&gt;
&lt;li&gt;one daily standup every workday&lt;/li&gt;
&lt;li&gt;everyone attends&lt;/li&gt;
&lt;li&gt;the realistic range is 30 minutes to 1 hour 30 minutes per day&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cost per engineer
&lt;/h3&gt;

&lt;p&gt;If the daily lasts &lt;strong&gt;30 minutes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;per week: &lt;code&gt;2.5 hours&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;per month: &lt;code&gt;10.8 hours&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;per year: &lt;code&gt;130 hours&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the daily lasts &lt;strong&gt;1 hour 30 minutes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;per week: &lt;code&gt;7.5 hours&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;per month: &lt;code&gt;32.5 hours&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;per year: &lt;code&gt;390 hours&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A single engineer can lose &lt;strong&gt;130 to 390 hours per year&lt;/strong&gt; to a ritual that is supposed to save time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing the waste
&lt;/h2&gt;

&lt;p&gt;The charts make the hidden tax easier to see.&lt;/p&gt;

&lt;h3&gt;
  
  
  6-person startup
&lt;/h3&gt;

&lt;p&gt;If the team has 6 people:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;30 minutes&lt;/strong&gt; per day = &lt;code&gt;780 hours&lt;/code&gt; per year&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 hour 30 minutes&lt;/strong&gt; per day = &lt;code&gt;2,340 hours&lt;/code&gt; per year&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is roughly &lt;strong&gt;0.4 to 1.1 full-time work-years&lt;/strong&gt; every year.&lt;/p&gt;

&lt;h3&gt;
  
  
  300-person company
&lt;/h3&gt;

&lt;p&gt;If the company has 300 people:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;30 minutes&lt;/strong&gt; per day = &lt;code&gt;39,000 hours&lt;/code&gt; per year&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 hour 30 minutes&lt;/strong&gt; per day = &lt;code&gt;117,000 hours&lt;/code&gt; per year&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is roughly &lt;strong&gt;18.8 to 56.3 full-time work-years&lt;/strong&gt; every year.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI changed
&lt;/h2&gt;

&lt;p&gt;AI did not remove the need for communication. It removed a lot of the manual work that used to justify the meeting.&lt;/p&gt;

&lt;p&gt;Teams can now get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better summaries&lt;/li&gt;
&lt;li&gt;faster blocker detection&lt;/li&gt;
&lt;li&gt;cleaner async updates&lt;/li&gt;
&lt;li&gt;more visible project state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the daily often becomes a low-value repetition of information people already have.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should replace it
&lt;/h2&gt;

&lt;p&gt;Not silence. Better communication.&lt;/p&gt;

&lt;p&gt;For most teams, that means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;async updates in Slack, Linear, Jira, or Notion&lt;/li&gt;
&lt;li&gt;clear ownership&lt;/li&gt;
&lt;li&gt;visible blockers&lt;/li&gt;
&lt;li&gt;short syncs only when a real decision or dependency needs conversation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the team still needs a live meeting, it should be because it is solving something that cannot be solved async.&lt;/p&gt;

&lt;p&gt;Reading yesterday’s task list is not that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule I would use
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;keep a daily only if it consistently removes blockers faster than async communication&lt;/li&gt;
&lt;li&gt;otherwise, replace it with written updates or a few syncs per week&lt;/li&gt;
&lt;li&gt;reserve live meetings for decisions, incidents, and real collaboration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Daily standups made sense when information was hard to see.&lt;/p&gt;

&lt;p&gt;In the AI era, they are often just a recurring tax on engineering time.&lt;/p&gt;

&lt;p&gt;If the meeting cannot prove its value, it should not survive by habit.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://oler.pages.dev/blog/why-daily-standups-are-becoming-useless-in-the-ai-era/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Foler.pages.dev%2Fog-images%2Fwhy-daily-standups-are-becoming-useless-in-the-ai-era.png" height="420" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://oler.pages.dev/blog/why-daily-standups-are-becoming-useless-in-the-ai-era/" rel="noopener noreferrer" class="c-link"&gt;
            Why Daily Standups Are Becoming Useless in the AI Era · Rodrigo Oler
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Daily standups used to be a coordination tool. Today, with better async workflows and AI-assisted status sharing, they often waste engineering time at scale.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Foler.pages.dev%2Ffavicon.svg" width="64" height="64"&gt;
          oler.pages.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>agile</category>
      <category>standup</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to Safely Remove Xcode Without Breaking Command Line Tools (CLT)</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Tue, 17 Jun 2025 19:01:18 +0000</pubDate>
      <link>https://forem.com/oler/how-to-safely-remove-xcode-without-breaking-command-line-tools-clt-191l</link>
      <guid>https://forem.com/oler/how-to-safely-remove-xcode-without-breaking-command-line-tools-clt-191l</guid>
      <description>&lt;p&gt;If you once built iOS/macOS apps but no longer need Xcode — or you simply want to free up tens of gigabytes of disk space — this guide shows how to safely remove Xcode without losing Command Line Tools (CLT) that keep your terminal environment working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Would You Remove Xcode?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Xcode occupies 10–30 GB depending on version and simulators.&lt;/li&gt;
&lt;li&gt;You no longer develop for iOS/macOS.&lt;/li&gt;
&lt;li&gt;You want to free SSD space but keep &lt;code&gt;git&lt;/code&gt;, &lt;code&gt;clang&lt;/code&gt;, &lt;code&gt;make&lt;/code&gt;, &lt;code&gt;brew&lt;/code&gt;, etc., functional.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Ensure Command Line Tools (CLT) Are Installed
&lt;/h2&gt;

&lt;p&gt;Before deleting Xcode, you must have CLT installed. Check with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xcode-select &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Applications/Xcode.app/Contents/Developer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means the CLT isn't set.&lt;/p&gt;

&lt;p&gt;To install CLT directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;softwareupdate &lt;span class="nt"&gt;--list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Find the latest Command Line Tools, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Label: Command Line Tools for Xcode-16.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install it:&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="nb"&gt;sudo &lt;/span&gt;softwareupdate &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"Command Line Tools for Xcode-16.4"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xcode-select &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Library/Developer/CommandLineTools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your CLI tools will work without Xcode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Remove Xcode Safely
&lt;/h2&gt;

&lt;p&gt;To fully remove Xcode:&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="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /Applications/Xcode.app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or simply drag &lt;code&gt;Xcode.app&lt;/code&gt; to the Trash via Finder and empty the Trash.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 (Optional): Free Additional Space
&lt;/h2&gt;

&lt;p&gt;Xcode leaves extra files. You can remove them:&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="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Developer/Xcode
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Caches/com.apple.dt.Xcode
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Xcode
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Preferences/com.apple.dt.Xcode.plist
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Developer/CoreSimulator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Warning: The last line removes all iOS simulators, if any remain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Reset Command Line Tools (if needed)
&lt;/h2&gt;

&lt;p&gt;If &lt;code&gt;xcode-select&lt;/code&gt; complains:&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="nb"&gt;sudo &lt;/span&gt;xcode-select &lt;span class="nt"&gt;--switch&lt;/span&gt; /Library/Developer/CommandLineTools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Confirm Everything Works
&lt;/h2&gt;

&lt;p&gt;Test key tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nt"&gt;--version&lt;/span&gt;
clang &lt;span class="nt"&gt;--version&lt;/span&gt;
make &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All should work fine without Xcode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Check CLT&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xcode-select -p&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install CLT via terminal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo softwareupdate -i "Command Line Tools for Xcode-XX.X"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove Xcode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo rm -rf /Applications/Xcode.app&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove extra files&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;rm -rf ~/Library/...&lt;/code&gt; (as listed above)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set CLT path manually&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo xcode-select --switch /Library/Developer/CommandLineTools&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify tools&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git --version&lt;/code&gt;, &lt;code&gt;clang --version&lt;/code&gt;, &lt;code&gt;make --version&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why This Is Useful
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Saves ~20 GB of space.&lt;/li&gt;
&lt;li&gt;Keeps Terminal fully working.&lt;/li&gt;
&lt;li&gt;Great for backend, Python, Rust, Go, or web developers who don’t build for Apple platforms anymore.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bonus: Automation Script
&lt;/h2&gt;

&lt;p&gt;Here’s a simple shell script to automate this process:&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;#!/bin/bash&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Checking for Command Line Tools..."&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; xcode-select &lt;span class="nt"&gt;-p&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; CommandLineTools&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Installing Command Line Tools..."&lt;/span&gt;
  &lt;span class="nv"&gt;latest_clt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;softwareupdate &lt;span class="nt"&gt;--list&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; 1 &lt;span class="s2"&gt;"Command Line Tools"&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1 | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt;&lt;span class="s1"&gt;'* Label: '&lt;/span&gt; &lt;span class="s1"&gt;'{print $2}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;softwareupdate &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$latest_clt&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Command Line Tools already installed."&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Removing Xcode..."&lt;/span&gt;
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /Applications/Xcode.app

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Cleaning extra files..."&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Developer/Xcode
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Caches/com.apple.dt.Xcode
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Xcode
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Preferences/com.apple.dt.Xcode.plist
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Developer/CoreSimulator

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Setting Command Line Tools path..."&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;xcode-select &lt;span class="nt"&gt;--switch&lt;/span&gt; /Library/Developer/CommandLineTools

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Done. Your Terminal environment is safe and clean!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>macos</category>
      <category>xcode</category>
      <category>terminal</category>
      <category>developertools</category>
    </item>
    <item>
      <title>How to free up space on your Mac's ssd (256GB)</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Sat, 08 Mar 2025 22:17:56 +0000</pubDate>
      <link>https://forem.com/oler/how-to-free-up-space-on-your-macs-ssd-256gb-1d1d</link>
      <guid>https://forem.com/oler/how-to-free-up-space-on-your-macs-ssd-256gb-1d1d</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%2Fhbr1jmmm9ealn6z1ljun.png" 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%2Fhbr1jmmm9ealn6z1ljun.png" alt="Wallpaper MacOS" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have a Mac with a 256GB SSD, you might notice that your storage fills up quickly. I managed to &lt;strong&gt;free up 100GB&lt;/strong&gt;, going from only &lt;strong&gt;20GB free to 120GB&lt;/strong&gt;! Here’s a simple guide to help you do the same, using a built-in Terminal command and the CleanMyMac app.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Find Big Files with &lt;code&gt;du&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;du&lt;/code&gt; (disk usage) command helps you see which folders and files are taking up the most space. Open &lt;strong&gt;Terminal&lt;/strong&gt; and type:&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="nb"&gt;cd&lt;/span&gt; ~  &lt;span class="c"&gt;# Go to your user folder&lt;/span&gt;

&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; .[^.]&lt;span class="k"&gt;*&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-hr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What does this command do?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;du -sh -- * .[^.]*&lt;/code&gt;: Shows the size of each file and folder, including hidden files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sort -hr&lt;/code&gt;: Sorts the results from largest to smallest, so you can easily find the biggest files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where to Look for Large Files
&lt;/h3&gt;

&lt;p&gt;Once you run the command, check these common storage hogs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/Downloads&lt;/code&gt;: Old downloads you no longer need.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/Library/Caches&lt;/code&gt;: App caches that build up over time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/Movies&lt;/code&gt; and &lt;code&gt;~/Music&lt;/code&gt;: Large media files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/Desktop&lt;/code&gt;: Temporary files left on your desktop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To delete files you no longer need, use:&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="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; path/to/file-or-folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Be careful!&lt;/strong&gt; Make sure you don’t delete important files.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Use CleanMyMac for Easy Cleanup
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://macpaw.com/cleanmymac" rel="noopener noreferrer"&gt;&lt;strong&gt;CleanMyMac&lt;/strong&gt;&lt;/a&gt; is a simple app that helps clean up your Mac automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Use CleanMyMac:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Download and install CleanMyMac from the official website.&lt;/li&gt;
&lt;li&gt;Open the app and click &lt;strong&gt;Smart Scan&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Review the files it suggests for deletion.&lt;/li&gt;
&lt;li&gt;Confirm the cleanup to free up space.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CleanMyMac removes junk files, app leftovers, and system caches safely.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. More Tips to Free Up Space
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🗑️ Empty the Trash
&lt;/h3&gt;

&lt;p&gt;Sometimes, files stay in the Trash and still take up space. Open &lt;strong&gt;Finder &amp;gt; Trash&lt;/strong&gt; and click &lt;strong&gt;Empty&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  🗃️ Manage iCloud Storage
&lt;/h3&gt;

&lt;p&gt;If you use iCloud Drive, old files might be taking up local space. Go to &lt;strong&gt;System Preferences &amp;gt; Apple ID &amp;gt; iCloud&lt;/strong&gt; and adjust storage settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Delete Unused Apps
&lt;/h3&gt;

&lt;p&gt;Check your installed apps in &lt;strong&gt;Finder &amp;gt; Applications&lt;/strong&gt; and delete ones you don’t need.&lt;/p&gt;




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

&lt;p&gt;By following these simple steps, you can easily &lt;strong&gt;free up gigabytes of space&lt;/strong&gt; on your Mac. The &lt;code&gt;du&lt;/code&gt; command helps you find large files, while CleanMyMac makes cleaning easy. &lt;/p&gt;

&lt;p&gt;Try it out and let me know if it worked for you! 🚀&lt;/p&gt;

</description>
      <category>mac</category>
      <category>cleanup</category>
      <category>ssd</category>
      <category>storage</category>
    </item>
    <item>
      <title>Fixing docker's malware warning on macOS Sequoia</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Thu, 09 Jan 2025 16:38:34 +0000</pubDate>
      <link>https://forem.com/oler/fixing-dockers-malware-warning-on-mac-os-sequoia-4fl4</link>
      <guid>https://forem.com/oler/fixing-dockers-malware-warning-on-mac-os-sequoia-4fl4</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%2Fxagvl3a8vwrscd6ob3u5.png" 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%2Fxagvl3a8vwrscd6ob3u5.png" alt="Docker Malware Warning on Mac" width="762" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently, while trying to open Docker locally on my Mac OS Sequoia (version 15.2), I encountered an error message indicating a "malware warning." This happened on January 9, 2025, and after a brief search on GitHub, I found a simple and effective solution to fix the issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Diagnosis
&lt;/h3&gt;

&lt;p&gt;The error was reported in &lt;a href="https://github.com/docker/for-mac/issues/7520" rel="noopener noreferrer"&gt;issue #7520 of the official Docker for Mac repository&lt;/a&gt;. In the thread of this issue, a user named &lt;a href="https://github.com/cdcaires" rel="noopener noreferrer"&gt;cdcaires&lt;/a&gt; shared a set of commands that resolved the problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;The commands to resolve the issue are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew uninstall &lt;span class="nt"&gt;--cask&lt;/span&gt; docker &lt;span class="nt"&gt;--force&lt;/span&gt;
brew uninstall &lt;span class="nt"&gt;--formula&lt;/span&gt; docker &lt;span class="nt"&gt;--force&lt;/span&gt;
brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What do these commands do?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;brew uninstall --cask docker --force&lt;/code&gt;&lt;/strong&gt;: Removes the cask version of Docker, even if it’s corrupted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;brew uninstall --formula docker --force&lt;/code&gt;&lt;/strong&gt;: Removes the CLI version of Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;brew install --cask docker&lt;/code&gt;&lt;/strong&gt;: Reinstalls the Docker Desktop application.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  How to Apply the Solution?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the Terminal on your Mac.&lt;/li&gt;
&lt;li&gt;Copy and paste the commands above, one by one.&lt;/li&gt;
&lt;li&gt;Ensure Docker is reinstalled without errors.&lt;/li&gt;
&lt;li&gt;Open Docker again. The malware warning should disappear.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;If you’ve encountered this issue in your development environment on Mac OS Sequoia, this solution should work. I hope this tip saves you time and avoids frustration!&lt;/p&gt;

&lt;p&gt;If you want to check the original discussion, here is the link to &lt;a href="https://github.com/docker/for-mac/issues/7520" rel="noopener noreferrer"&gt;issue #7520 on GitHub&lt;/a&gt; and the &lt;a href="https://github.com/docker/for-mac/issues/7520#issuecomment-2580337894" rel="noopener noreferrer"&gt;comment with the solution&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>macos</category>
      <category>vmnetd</category>
      <category>malware</category>
    </item>
    <item>
      <title>Introduction to @let in Angular 18</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Tue, 21 May 2024 19:17:19 +0000</pubDate>
      <link>https://forem.com/oler/introduction-to-let-in-angular-18-cm6</link>
      <guid>https://forem.com/oler/introduction-to-let-in-angular-18-cm6</guid>
      <description>&lt;p&gt;Angular 18 has an exciting new feature under development for developers: the &lt;code&gt;@let&lt;/code&gt; directive. This tool will help you create variables quickly and easily within HTML code. It's important to note that &lt;strong&gt;this feature is still being developed and has not yet been merged into a release within Angular 18&lt;/strong&gt;. Let's understand how it works and look at some cool examples of its potential use.&lt;/p&gt;

&lt;p&gt;Update: According to a comment by Denes Papp on dev.to, the merge has now happened in version 18.1.0, and the &lt;code&gt;@let&lt;/code&gt; directive is now official. For more details and useful links, you can check out his comment &lt;a href="https://dev.to/pppdns/comment/2gj48"&gt;here&lt;/a&gt;. Thanks to &lt;a href="https://dev.to/pppdns"&gt;Denes&lt;/a&gt; for the update!&lt;/p&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;@let&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;@let&lt;/code&gt; directive allows you to create variables directly in the HTML code. This means you can do simple operations like joining text or calculations without needing to write more complex code elsewhere in your program.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Use &lt;code&gt;@let&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Here’s a simple example:&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;div&amp;gt;&lt;/span&gt;
  @let greeting = 'Hello, ' + name + '!';
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{{ greeting }}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we are creating a variable &lt;code&gt;greeting&lt;/code&gt; that concatenates the string "Hello, " with the variable &lt;code&gt;name&lt;/code&gt;, and then we display it on the screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage Examples
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Calculating Total Prices
&lt;/h4&gt;

&lt;p&gt;Imagine you have a list of products and you want to show the total price of each one. You can do it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@for (product of products; track product.id) {
  @let totalPrice = product.price * product.quantity;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ product.name }} - Total: {{ totalPrice | currency }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;totalPrice&lt;/code&gt; is calculated by multiplying the product’s price (&lt;code&gt;product.price&lt;/code&gt;) by the quantity (&lt;code&gt;product.quantity&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Formatting Dates
&lt;/h4&gt;

&lt;p&gt;You can format dates easily. Suppose you have a list of events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@for (event of events; track event.id) {
  @let formattedDate = (new Date(event.date)).toLocaleDateString();
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ event.name }} - Date: {{ formattedDate }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;formattedDate&lt;/code&gt; converts the event date (&lt;code&gt;event.date&lt;/code&gt;) to a more readable format.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Showing Messages Based on Conditions
&lt;/h4&gt;

&lt;p&gt;You can create messages based on conditions, like checking if a user is active:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@for (user of users; track user.id) {
  @let statusMessage = user.isActive ? 'Active' : 'Inactive';
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ user.name }} - Status: {{ statusMessage }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;statusMessage&lt;/code&gt; is set to "Active" if the user is active (&lt;code&gt;user.isActive&lt;/code&gt;), or "Inactive" if not.&lt;/p&gt;

&lt;h3&gt;
  
  
  More Complex Examples
&lt;/h3&gt;

&lt;h4&gt;
  
  
  4. Calculating Average Grades
&lt;/h4&gt;

&lt;p&gt;Let’s calculate the average grades of students:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@for (student of students; track student.id) {
  @let total = student.grades.reduce((sum, grade) =&amp;gt; sum + grade, 0);
  @let average = total / student.grades.length;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ student.name }} - Average: {{ average.toFixed(2) }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we calculate the sum of the grades (&lt;code&gt;total&lt;/code&gt;) and then the average (&lt;code&gt;average&lt;/code&gt;), displaying it with two decimal places (&lt;code&gt;toFixed(2)&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Filtering Items in a List
&lt;/h4&gt;

&lt;p&gt;Suppose you want to show only the available products:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@for (product of products; track product.id) {
  @let isAvailable = product.stock &amp;gt; 0;
  @if (isAvailable) {
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ product.name }} - In stock: {{ product.stock }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;isAvailable&lt;/code&gt; checks if the product has stock (&lt;code&gt;product.stock &amp;gt; 0&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of &lt;code&gt;@let&lt;/code&gt; with &lt;code&gt;| async&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;One of the challenges in Angular before the introduction of &lt;code&gt;@let&lt;/code&gt; was handling asynchronous data, especially when dealing with observables. Typically, you would use the &lt;code&gt;| async&lt;/code&gt; pipe, but this often required additional directives like &lt;code&gt;*ngIf&lt;/code&gt; to avoid undefined values, or you had to create extra components or subscribe manually in the TypeScript code.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;@let&lt;/code&gt;, handling async data becomes more straightforward and elegant:&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;div&amp;gt;&lt;/span&gt;
  @let data = (data$ | async);
  @let processedData = data ? data.map(item =&amp;gt; item.value) : [];
  &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    @for (item of processedData; track item) {
      &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;{{ item }}&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    }
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;data$&lt;/code&gt; is an observable, and using &lt;code&gt;@let&lt;/code&gt;, we can directly process the asynchronous data within the template without needing extra directives or subscriptions. The &lt;code&gt;@let&lt;/code&gt; directive handles the async pipe and processes the data in a more readable and concise way.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Not to Use &lt;code&gt;@let&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Although &lt;code&gt;@let&lt;/code&gt; is very useful, there are times when it’s not the best choice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Complex Logic&lt;/strong&gt;: If the logic you need is very complicated, it’s better to do it in TypeScript, outside the template.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusability&lt;/strong&gt;: If you need to use the same logic in multiple places, it’s more efficient to create a function or method in the component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: In some situations, especially with many items, &lt;code&gt;@let&lt;/code&gt; can impact performance. It’s important to test and make sure everything is running fast.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@let&lt;/code&gt; in Angular 18 is a powerful and easy-to-use tool that helps simplify code. With it, you can create local variables directly in HTML, making your code cleaner and easier to understand. Use &lt;code&gt;@let&lt;/code&gt; for simple operations and keep complex logic in TypeScript. This way, you get the best of both worlds!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>angular18</category>
      <category>front</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Resolving viewport duplication in Next.js 13.4</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Sat, 22 Jul 2023 00:56:06 +0000</pubDate>
      <link>https://forem.com/oler/resolving-viewport-duplication-in-nextjs-134-51lm</link>
      <guid>https://forem.com/oler/resolving-viewport-duplication-in-nextjs-134-51lm</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%2Fqqk50mjp94k64p5iavaf.png" 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%2Fqqk50mjp94k64p5iavaf.png" alt="nextjs" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;The Problem&lt;/li&gt;
&lt;li&gt;The Solution&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;When working with Next.js, it's common to encounter some technical issues along the way. One such problem that may arise is the duplication of the viewport tag. This article aims to address this issue specifically, providing a solution to resolve the viewport duplication problem in components in Next.js 13.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Before we present the solution, it's crucial to first understand the problem at hand. When using the viewport tag directly in the code, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./globals.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/font/google&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;viewport&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width=device-width, initial-scale=1, maximum-scale=1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;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%2Fgytcieg8lsmi1y0pdl8y.png" 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%2Fgytcieg8lsmi1y0pdl8y.png" alt="warning" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;To solve this problem, we need to change the way we are defining the viewport. Instead of placing it directly in the code, we should specify it in the metadata.&lt;/p&gt;

&lt;p&gt;The solution was discovered and documented in a &lt;a href="https://stackoverflow.com/questions/76740487/override-meta-tags-in-nextjs-13-4/76740673#76740673" rel="noopener noreferrer"&gt;StackOverflow thread&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./globals.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/font/google&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Create Next App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generated by create next app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;width=device-width, initial-scale=1, maximum-scale=1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- now here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;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%2F2pgyvwij5sh6khz1ujvd.png" 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%2F2pgyvwij5sh6khz1ujvd.png" alt="success" width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;In the world of software development, we often come across technical challenges. These challenges may seem daunting at first glance, but with the power of the development community and the constant exchange of knowledge, the solution is often just a post away.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Resolvendo a duplicidade do viewport no Next.js 13.4</title>
      <dc:creator>Rodrigo Oler</dc:creator>
      <pubDate>Sat, 22 Jul 2023 00:22:46 +0000</pubDate>
      <link>https://forem.com/oler/resolvendo-a-duplicidade-do-viewport-no-nextjs-134-3hki</link>
      <guid>https://forem.com/oler/resolvendo-a-duplicidade-do-viewport-no-nextjs-134-3hki</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%2Fqqk50mjp94k64p5iavaf.png" 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%2Fqqk50mjp94k64p5iavaf.png" alt="nextjs" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Introdução&lt;/li&gt;
&lt;li&gt;O Problema&lt;/li&gt;
&lt;li&gt;A Solução&lt;/li&gt;
&lt;li&gt;Conclusão&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Quando trabalhamos com o Next.js, é comum encontrar alguns problemas técnicos ao longo do caminho. Um desses problemas que pode surgir é a duplicidade da tag viewport. Este artigo tem como objetivo abordar especificamente essa questão, fornecendo uma solução para resolver o problema da duplicidade do viewport em components no Next.js 13.&lt;/p&gt;




&lt;h2&gt;
  
  
  O Problema
&lt;/h2&gt;

&lt;p&gt;Antes de apresentarmos a solução, é crucial entender primeiro o problema em mãos. Ao utilizar a tag do viewport diretamente no código, como mostrado abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./globals.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/font/google&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;viewport&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width=device-width, initial-scale=1, maximum-scale=1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;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%2Fgytcieg8lsmi1y0pdl8y.png" 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%2Fgytcieg8lsmi1y0pdl8y.png" alt="warning" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  A Solução
&lt;/h2&gt;

&lt;p&gt;Para resolver este problema, precisamos mudar a forma como estamos definindo a viewport. Em vez de colocá-la diretamente no código, devemos especificá-la no metadata.&lt;/p&gt;

&lt;p&gt;A solução foi descoberta e documentada em um &lt;a href="https://stackoverflow.com/questions/76740487/override-meta-tags-in-nextjs-13-4/76740673#76740673" rel="noopener noreferrer"&gt;tópico no StackOverflow&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./globals.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/font/google&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Create Next App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generated by create next app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;width=device-width, initial-scale=1, maximum-scale=1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- now here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReactNode&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;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%2F2pgyvwij5sh6khz1ujvd.png" 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%2F2pgyvwij5sh6khz1ujvd.png" alt="success" width="800" height="295"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;No mundo do desenvolvimento de software, muitas vezes nos deparamos com desafios técnicos. Esses desafios podem parecer intimidantes à primeira vista, mas com o poder da comunidade de desenvolvimento e a troca constante de conhecimentos, a solução está frequentemente a apenas um post de distância.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
