<?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>DEV Community: Douglas Moura</title>
    <description>The latest articles on DEV Community by Douglas Moura (@douglasdemoura).</description>
    <link>https://dev.to/douglasdemoura</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F281088%2F51819a33-cf39-4bea-9205-987cd5052433.jpg</url>
      <title>DEV Community: Douglas Moura</title>
      <link>https://dev.to/douglasdemoura</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/douglasdemoura"/>
    <language>en</language>
    <item>
      <title>Introducing chroncal: A Terminal-First Calendar, Todo, and Journal Manager</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Sun, 14 Jun 2026 13:44:04 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/introducing-chroncal-a-terminal-first-calendar-todo-and-journal-manager-149n</link>
      <guid>https://dev.to/douglasdemoura/introducing-chroncal-a-terminal-first-calendar-todo-and-journal-manager-149n</guid>
      <description>&lt;p&gt;I have been building &lt;a href="https://github.com/DouglasdeMoura/chroncal" rel="noopener noreferrer"&gt;chroncal&lt;/a&gt; over the past several weeks, and today I am opening it up. It is a terminal calendar, todo, and journal manager written in Go, backed by SQLite, with broad iCalendar (RFC 5545) import/export coverage and CalDAV sync. You get an interactive TUI for day-to-day use and a full CLI for scripting and automation. Your data lives in a single local file, portable and standards-compliant.&lt;/p&gt;

&lt;p&gt;This is the tool I wanted for myself: something that feels like &lt;code&gt;lazygit&lt;/code&gt; for calendars, works offline, talks to CalDAV servers (including Google Calendar), and stays out of the way when I just want to check my next meeting.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;chroncal covers three resource types that normally live in separate apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Events&lt;/strong&gt; (VEVENT) — scheduling with recurrence, timezones, attendees, alarms, and attachments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Todos&lt;/strong&gt; (VTODO) — task management with due dates, priority, progress tracking, and recurrence&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Journals&lt;/strong&gt; (VJOURNAL) — daily notes and journal entries with recurrence support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three support create, read, update, delete, search, and iCal import/export. All three sync over CalDAV. Soft-delete and restore are built in, so nothing is lost by accident.&lt;/p&gt;

&lt;h2&gt;
  
  
  The TUI
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;chroncal&lt;/code&gt; with no arguments and you get an interactive terminal interface with month, week, day, and agenda views. Switch views with &lt;code&gt;m&lt;/code&gt;, &lt;code&gt;w&lt;/code&gt;, &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt;. Calendars live in a sidebar with color coding. You can create, edit, view, and delete events without leaving the keyboard, and &lt;code&gt;u&lt;/code&gt; undoes a delete.&lt;/p&gt;

&lt;p&gt;CalDAV sync health is visible at a glance: a calendar whose last sync failed shows a warning icon in the sidebar, and opening it explains what went wrong and offers a fix. Remote calendars can be connected and re-authenticated directly from the TUI, including the Google OAuth flow.&lt;/p&gt;

&lt;p&gt;The TUI ships two built-in themes. &lt;code&gt;system&lt;/code&gt; is the default and resolves its UI colors from your terminal's 16-color ANSI palette, so themed setups like Catppuccin, Gruvbox, Tokyo Night, or Omarchy carry through to chroncal. It also adapts the selected-row highlight to the live terminal background when the terminal reports it. &lt;code&gt;default&lt;/code&gt; uses a fixed light/dark designer palette if you prefer a consistent look across machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CLI
&lt;/h2&gt;

&lt;p&gt;Every operation available in the TUI is also available as a CLI command, and the CLI goes further — full todo and journal management live here. This makes chroncal scriptable in ways that GUI calendar apps cannot match.&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;# Create a calendar&lt;/span&gt;
chroncal calendar create &lt;span class="s2"&gt;"Work"&lt;/span&gt; &lt;span class="nt"&gt;--color&lt;/span&gt; &lt;span class="s2"&gt;"#3B82F6"&lt;/span&gt;

&lt;span class="c"&gt;# Add an event&lt;/span&gt;
chroncal event add &lt;span class="s2"&gt;"Team standup"&lt;/span&gt; &lt;span class="nt"&gt;--date&lt;/span&gt; 2026-04-01 &lt;span class="nt"&gt;--time&lt;/span&gt; 09:00 &lt;span class="nt"&gt;--duration&lt;/span&gt; 30m &lt;span class="nt"&gt;--calendar&lt;/span&gt; Work

&lt;span class="c"&gt;# Add a recurring event&lt;/span&gt;
chroncal event add &lt;span class="s2"&gt;"Weekly review"&lt;/span&gt; &lt;span class="nt"&gt;--date&lt;/span&gt; 2026-04-04 &lt;span class="nt"&gt;--time&lt;/span&gt; 14:00 &lt;span class="nt"&gt;--duration&lt;/span&gt; 1h &lt;span class="nt"&gt;--rrule&lt;/span&gt; &lt;span class="s2"&gt;"FREQ=WEEKLY;BYDAY=FR"&lt;/span&gt;

&lt;span class="c"&gt;# Add a todo&lt;/span&gt;
chroncal todo add &lt;span class="s2"&gt;"Write quarterly report"&lt;/span&gt; &lt;span class="nt"&gt;--due&lt;/span&gt; 2026-04-15 &lt;span class="nt"&gt;--priority&lt;/span&gt; 1

&lt;span class="c"&gt;# Add a journal entry&lt;/span&gt;
chroncal journal add &lt;span class="s2"&gt;"Weekly notes"&lt;/span&gt; &lt;span class="nt"&gt;--date&lt;/span&gt; 2026-04-04 &lt;span class="nt"&gt;--calendar&lt;/span&gt; Work

&lt;span class="c"&gt;# List upcoming events&lt;/span&gt;
chroncal event list &lt;span class="nt"&gt;--from&lt;/span&gt; 2026-04-01 &lt;span class="nt"&gt;--to&lt;/span&gt; 2026-04-30

&lt;span class="c"&gt;# Search&lt;/span&gt;
chroncal event search &lt;span class="s2"&gt;"standup"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JSON output for scripts and LLMs
&lt;/h3&gt;

&lt;p&gt;Every command accepts &lt;code&gt;-o json&lt;/code&gt; (or &lt;code&gt;--output json&lt;/code&gt;). The output shape is stable, write commands return the new row so you can capture the &lt;code&gt;id&lt;/code&gt; or &lt;code&gt;uid&lt;/code&gt;, and errors go to stderr so piping through &lt;code&gt;jq&lt;/code&gt; is always safe.&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;# Round-trip: create then read back the new event&lt;/span&gt;
&lt;span class="nv"&gt;uid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;chroncal event add &lt;span class="s2"&gt;"Demo"&lt;/span&gt; &lt;span class="nt"&gt;--date&lt;/span&gt; 2026-06-01 &lt;span class="nt"&gt;--time&lt;/span&gt; 09:00 &lt;span class="nt"&gt;--output&lt;/span&gt; json | jq &lt;span class="nt"&gt;-r&lt;/span&gt; .uid&lt;span class="si"&gt;)&lt;/span&gt;
chroncal event get &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$uid&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Timestamps in JSON are RFC 3339 UTC with a &lt;code&gt;Z&lt;/code&gt; suffix, so cross-machine comparisons stay honest. Errors emit a JSON object on stderr with a &lt;code&gt;code&lt;/code&gt; field (&lt;code&gt;not_found&lt;/code&gt;, &lt;code&gt;invalid_input&lt;/code&gt;, &lt;code&gt;aborted&lt;/code&gt;, or &lt;code&gt;error&lt;/code&gt;), so you can dispatch programmatically. This makes chroncal straightforward to drive from shell scripts, CI pipelines, or language model agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  CalDAV sync
&lt;/h2&gt;

&lt;p&gt;Sync is per-calendar: each local calendar can be linked to a remote CalDAV URL. There is no separate account concept. Connect a calendar at create time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chroncal calendar create &lt;span class="s2"&gt;"Work"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--remote-url&lt;/span&gt; https://cal.example.com/dav/calendars/work/ &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--username&lt;/span&gt; alice &lt;span class="nt"&gt;--auth&lt;/span&gt; basic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then sync and check status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chroncal &lt;span class="nb"&gt;sync &lt;/span&gt;run &lt;span class="nt"&gt;--calendar&lt;/span&gt; Work
chroncal &lt;span class="nb"&gt;sync &lt;/span&gt;status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;chroncal has been tested against Nextcloud CalDAV with VEVENT, VTODO, VJOURNAL, and VALARM round-tripping, including recurrence, timezone handling, and conflict resolution. Conflicts can be resolved with &lt;code&gt;--pick {local,server}&lt;/code&gt;, and the default strategy is configurable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Google Calendar
&lt;/h3&gt;

&lt;p&gt;Google Calendar requires OAuth 2.0 and only supports VEVENT over CalDAV. chroncal handles the full OAuth PKCE flow: you provide a Desktop app client ID and secret (the secret is accepted via environment variable or interactive prompt, never as a CLI flag), authorize once in the browser, and subsequent syncs run unattended. You can also connect and re-authenticate Google calendars directly from the TUI.&lt;/p&gt;

&lt;p&gt;One important detail: you must enable both the Calendar JSON API and the CalDAV API on your Google Cloud project. The CalDAV endpoint returns &lt;code&gt;403 accessNotConfigured&lt;/code&gt; until &lt;code&gt;caldav.googleapis.com&lt;/code&gt; is enabled, even if the Calendar API is already on.&lt;/p&gt;

&lt;p&gt;Credentials are kept separate from the calendar database. SQLite stores calendar data and remote metadata, but passwords, bearer tokens, OAuth refresh tokens, and Google client secrets go through the OS keyring by default. If a keyring is not available, chroncal refuses to store secrets unless you explicitly pass &lt;code&gt;--allow-plaintext&lt;/code&gt;; that fallback writes &lt;code&gt;0600&lt;/code&gt; JSON files under your chroncal config directory. It is useful for servers and containers, but backups and sync tools can still read those files, so I recommend using a real keyring on shared machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alarms and notifications
&lt;/h2&gt;

&lt;p&gt;Alarms are first-class. Attach them when creating or updating events and todos with &lt;code&gt;--alarm&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chroncal event add &lt;span class="s2"&gt;"Standup"&lt;/span&gt; &lt;span class="nt"&gt;--date&lt;/span&gt; 2026-06-15 &lt;span class="nt"&gt;--time&lt;/span&gt; 09:00 &lt;span class="nt"&gt;--alarm&lt;/span&gt; &lt;span class="s2"&gt;"-PT15M"&lt;/span&gt;
chroncal event add &lt;span class="s2"&gt;"Release"&lt;/span&gt; &lt;span class="nt"&gt;--date&lt;/span&gt; 2026-06-15 &lt;span class="nt"&gt;--time&lt;/span&gt; 14:00 &lt;span class="nt"&gt;--alarm&lt;/span&gt; &lt;span class="s2"&gt;"DISPLAY:-PT30M::3:PT5M"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The alarm syntax maps to RFC 5545 &lt;code&gt;VALARM&lt;/code&gt;: &lt;code&gt;ACTION&lt;/code&gt;, &lt;code&gt;TRIGGER&lt;/code&gt;, &lt;code&gt;REPEAT&lt;/code&gt;, &lt;code&gt;DURATION&lt;/code&gt;, and &lt;code&gt;RELATED&lt;/code&gt;. A bare &lt;code&gt;-PT15M&lt;/code&gt; is a standard iCalendar duration trigger, meaning 15 minutes before the event or todo starts. The longer form is there when you need repeated alarms or an alarm relative to the end instead of the start.&lt;/p&gt;

&lt;p&gt;DISPLAY alarms pop desktop notifications, AUDIO alarms play a sound, and EMAIL alarms send mail through a configured SMTP server. To actually fire alarms, either run &lt;code&gt;chroncal alarm daemon&lt;/code&gt; in a foreground loop, or install a background service with &lt;code&gt;chroncal service install&lt;/code&gt; — which sets up a systemd timer on Linux, launchd agent on macOS, or Scheduled Task on Windows. The installed service also runs CalDAV sync on a configurable interval (default 15 minutes).&lt;/p&gt;

&lt;h2&gt;
  
  
  iCal compatibility
&lt;/h2&gt;

&lt;p&gt;chroncal aims for complete RFC 5545 compliance. Current coverage includes VEVENT (30/31 properties), VTODO (31/32 properties), VJOURNAL, VALARM (7/7 properties plus RFC 9074 UID support), full ATTENDEE/ORGANIZER parameter coverage, VTIMEZONE round-trip preservation, and VFREEBUSY local compute plus remote CalDAV queries.&lt;/p&gt;

&lt;p&gt;You can import from Google Calendar, Apple Calendar, Thunderbird, or any RFC 5545-compliant source, and export produces standards-compliant &lt;code&gt;.ics&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chroncal ical import calendar.ics &lt;span class="nt"&gt;--calendar&lt;/span&gt; Work
chroncal ical &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nt"&gt;--calendar&lt;/span&gt; Work &lt;span class="nt"&gt;-f&lt;/span&gt; work.ics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Free/busy queries
&lt;/h2&gt;

&lt;p&gt;Compute busy time from local recurring data, or query a remote CalDAV server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chroncal freebusy &lt;span class="nt"&gt;--calendar&lt;/span&gt; Work &lt;span class="nt"&gt;--from&lt;/span&gt; 2026-04-01 &lt;span class="nt"&gt;--to&lt;/span&gt; 2026-04-30
chroncal freebusy &lt;span class="nt"&gt;--calendar&lt;/span&gt; Work &lt;span class="nt"&gt;--from&lt;/span&gt; 2026-04-01 &lt;span class="nt"&gt;--to&lt;/span&gt; 2026-04-30 &lt;span class="nt"&gt;--remote&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;chroncal is available through eight installation channels covering Linux, macOS, and Windows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Platforms&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Install script&lt;/td&gt;
&lt;td&gt;Linux, macOS, FreeBSD, OpenBSD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Homebrew&lt;/td&gt;
&lt;td&gt;macOS, Linux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go install&lt;/td&gt;
&lt;td&gt;Any platform with Go 1.25+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mise&lt;/td&gt;
&lt;td&gt;macOS, Linux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nix&lt;/td&gt;
&lt;td&gt;Linux, macOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scoop&lt;/td&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AUR&lt;/td&gt;
&lt;td&gt;Arch Linux&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build from source&lt;/td&gt;
&lt;td&gt;Any platform with Go 1.25+&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The quickest path on Linux or macOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/DouglasdeMoura/chroncal/master/scripts/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with Homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap douglasdemoura/tap &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew &lt;span class="nb"&gt;install &lt;/span&gt;chroncal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows, the managed install path is Scoop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;scoop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chroncal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://github.com/DouglasdeMoura/scoop-bucket&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;scoop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chroncal&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you use &lt;a href="https://douglasmoura.dev/managing-your-development-environment-with-mise" rel="noopener noreferrer"&gt;mise&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise use &lt;span class="nt"&gt;-g&lt;/span&gt; github:DouglasdeMoura/chroncal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;chroncal also has a custom app icon for launchers:&lt;/p&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%2F33j232w7myi8a4coemqv.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%2F33j232w7myi8a4coemqv.png" alt="chroncal app icon" width="512" height="512"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;If you use &lt;a href="https://omarchy.org/" rel="noopener noreferrer"&gt;Omarchy&lt;/a&gt;, you can add chroncal to the app menu with one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omarchy tui &lt;span class="nb"&gt;install &lt;/span&gt;chroncal chroncal float https://raw.githubusercontent.com/DouglasdeMoura/chroncal/master/assets/chroncal-512.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That creates a launcher item that opens chroncal in your configured terminal. The &lt;code&gt;float&lt;/code&gt; style opens it in a centered floating window; use &lt;code&gt;tile&lt;/code&gt; if you want it to behave like a normal tiled window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data storage
&lt;/h2&gt;

&lt;p&gt;The database is a single SQLite file with WAL mode enabled for concurrency. Migrations run automatically on startup. Default locations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linux&lt;/strong&gt;: &lt;code&gt;~/.local/share/chroncal/chroncal.db&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS&lt;/strong&gt;: &lt;code&gt;~/Library/Application Support/chroncal/chroncal.db&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Override with &lt;code&gt;CHRONCAL_DB&lt;/code&gt; or the &lt;code&gt;db&lt;/code&gt; key in &lt;code&gt;config.toml&lt;/code&gt;. Because it is a single file, backing up or moving your calendar data is a file copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next
&lt;/h2&gt;

&lt;p&gt;chroncal is at v0.3.x and MIT-licensed. The core feature set — events, todos, journals, CalDAV sync, alarms, iCal import/export, full-text search, and recurring rules — is working and tested. Todo and journal management in the TUI is the next major focus, along with &lt;code&gt;.deb&lt;/code&gt; and &lt;code&gt;.rpm&lt;/code&gt; packages.&lt;/p&gt;

&lt;p&gt;If you live in the terminal and want your calendar data local, portable, and scriptable, give it a try. The repository is at &lt;a href="https://github.com/DouglasdeMoura/chroncal" rel="noopener noreferrer"&gt;github.com/DouglasdeMoura/chroncal&lt;/a&gt;, and issues and contributions are welcome.&lt;/p&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%2Fk08iihr9gvdpmsqcnajd.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%2Fk08iihr9gvdpmsqcnajd.png" alt="Integrating chroncal with Omarchy" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>cli</category>
      <category>tui</category>
      <category>calendar</category>
    </item>
    <item>
      <title>Aube: A New Dawn for Node Installs</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Mon, 08 Jun 2026 03:00:00 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/aube-a-new-dawn-for-node-installs-1o27</link>
      <guid>https://dev.to/douglasdemoura/aube-a-new-dawn-for-node-installs-1o27</guid>
      <description>&lt;p&gt;&lt;a href="https://aube.en.dev/" rel="noopener noreferrer"&gt;Aube&lt;/a&gt; (pronounced "ohb", from the French word for dawn) is a new Node.js package manager written in Rust by &lt;a href="https://github.com/endevco" rel="noopener noreferrer"&gt;en.dev&lt;/a&gt;, the same developer behind &lt;a href="https://douglasmoura.dev/managing-your-development-environment-with-mise" rel="noopener noreferrer"&gt;Mise&lt;/a&gt;. It reads and writes your existing lockfile (&lt;code&gt;pnpm-lock.yaml&lt;/code&gt;, &lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;npm-shrinkwrap.json&lt;/code&gt;, &lt;code&gt;yarn.lock&lt;/code&gt;, or &lt;code&gt;bun.lock&lt;/code&gt;) in place, so you can try it in a project without forcing your team to switch package managers. I started using it this week, and I want to share my thoughts on the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed
&lt;/h2&gt;

&lt;p&gt;Aube starts from pnpm's isolated symlink model: package files live in a global content-addressable store, and projects link to them through an isolated &lt;code&gt;node_modules&lt;/code&gt; layout. Aube also enables its global virtual store by default for local installs, while pnpm leaves its comparable feature off by default. The results show in the current benchmarks against a ~1400-package real-world fixture:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;aube&lt;/th&gt;
&lt;th&gt;bun&lt;/th&gt;
&lt;th&gt;deno&lt;/th&gt;
&lt;th&gt;pnpm&lt;/th&gt;
&lt;th&gt;npm&lt;/th&gt;
&lt;th&gt;yarn&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fresh install (warm cache)&lt;/td&gt;
&lt;td&gt;272 ms&lt;/td&gt;
&lt;td&gt;2.00 s&lt;/td&gt;
&lt;td&gt;1.33 s&lt;/td&gt;
&lt;td&gt;2.34 s&lt;/td&gt;
&lt;td&gt;7.14 s&lt;/td&gt;
&lt;td&gt;8.86 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fresh install (cold cache)&lt;/td&gt;
&lt;td&gt;7.95 s&lt;/td&gt;
&lt;td&gt;5.78 s&lt;/td&gt;
&lt;td&gt;8.15 s&lt;/td&gt;
&lt;td&gt;15.87 s&lt;/td&gt;
&lt;td&gt;9.51 s&lt;/td&gt;
&lt;td&gt;13.19 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;install &amp;amp;&amp;amp; test&lt;/code&gt; (already installed)&lt;/td&gt;
&lt;td&gt;9 ms&lt;/td&gt;
&lt;td&gt;41 ms&lt;/td&gt;
&lt;td&gt;84 ms&lt;/td&gt;
&lt;td&gt;335 ms&lt;/td&gt;
&lt;td&gt;745 ms&lt;/td&gt;
&lt;td&gt;1.18 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The cold-cache number still trails Bun, but the warm-cache and repeat-command numbers are where aube pulls ahead. The &lt;code&gt;install &amp;amp;&amp;amp; test&lt;/code&gt; row is the developer loop: aube can skip install work when its install-state file is fresh, so repeated &lt;code&gt;aubr test&lt;/code&gt; runs land in single-digit milliseconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lockfile compatibility
&lt;/h2&gt;

&lt;p&gt;This is the part that caught my attention. Aube does not introduce its own lockfile format unless you want it to. If your project already has &lt;code&gt;pnpm-lock.yaml&lt;/code&gt;, aube reads and writes it back in place. Same for &lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;npm-shrinkwrap.json&lt;/code&gt;, &lt;code&gt;yarn.lock&lt;/code&gt;, and &lt;code&gt;bun.lock&lt;/code&gt;. That means you can run &lt;code&gt;aubr test&lt;/code&gt; in a pnpm project today and your teammates who use pnpm will not notice a difference.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lockfile&lt;/th&gt;
&lt;th&gt;Reads&lt;/th&gt;
&lt;th&gt;Writes in place&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;aube-lock.yaml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;pnpm-lock.yaml&lt;/code&gt; v9&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;package-lock.json&lt;/code&gt; v2/v3&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm-shrinkwrap.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;yarn.lock&lt;/code&gt; (v1 classic + v2+ berry)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bun.lock&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a new project with no lockfile, aube creates &lt;code&gt;aube-lock.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;aubr&lt;/code&gt; and &lt;code&gt;aubx&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;aubr&lt;/code&gt; is shorthand for &lt;code&gt;aube run&lt;/code&gt;. Before running a script, it checks whether &lt;code&gt;node_modules&lt;/code&gt; is fresh for the current &lt;code&gt;package.json&lt;/code&gt; and lockfile. If dependencies are missing or stale, it installs them first; otherwise it skips straight to the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aubr &lt;span class="nb"&gt;test
&lt;/span&gt;aubr build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;aubx&lt;/code&gt; is shorthand for &lt;code&gt;aube dlx&lt;/code&gt;. It prefers an installed local binary before fetching into a throwaway environment. Useful for one-off tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aubx cowsay hi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both are multicall shims that share the same binary as &lt;code&gt;aube&lt;/code&gt; and dispatch on &lt;code&gt;argv[0]&lt;/code&gt;. Every flag that works on the full command also works on the shim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Less disk usage
&lt;/h2&gt;

&lt;p&gt;Like pnpm, aube keeps package files in a global content-addressable store (&lt;code&gt;~/.local/share/aube/store/&lt;/code&gt;) and links projects to it. Three apps that depend on React, Vite, TypeScript, and Playwright share the heavy files instead of storing three full copies. Aube claims up to 90% less disk usage compared to npm's approach of copying dependencies into every project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security defaults
&lt;/h2&gt;

&lt;p&gt;Aube ships with several supply-chain protections turned on by default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trust policy&lt;/strong&gt; (&lt;code&gt;trustPolicy: no-downgrade&lt;/code&gt;) — blocks installs of a version that carries weaker trust evidence than any earlier-published version of the same package. A trust downgrade may indicate account takeover, repository tampering, or a malicious co-maintainer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimum release age&lt;/strong&gt; — 24-hour cooldown on newly published versions by default (&lt;code&gt;minimumReleaseAge: 1440&lt;/code&gt;). Catches typo-squat and dependency-confusion attacks that get unpublished within hours.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default-deny lifecycle scripts&lt;/strong&gt; — dependency lifecycle scripts (&lt;code&gt;preinstall&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;, &lt;code&gt;postinstall&lt;/code&gt;) do not run unless you approve them explicitly via &lt;code&gt;aube approve-builds&lt;/code&gt;. A suspicious-script content sniff warns about known-dangerous patterns like &lt;code&gt;curl | sh&lt;/code&gt;, base64-decode-then-evaluate, and reads of credential files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional jailed builds&lt;/strong&gt; — when &lt;code&gt;jailBuilds: true&lt;/code&gt; is enabled and a dependency is approved to build, aube can wrap the script with a Seatbelt profile (macOS), Landlock and seccomp (Linux), or a scrubbed environment (Windows) to deny network access and limit filesystem writes. This is included in &lt;code&gt;paranoid: true&lt;/code&gt;, but it is not the default today.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typosquat protection&lt;/strong&gt; — &lt;code&gt;aube add&lt;/code&gt; checks the package you add and the resolved transitive dependency graph against OSV for &lt;code&gt;MAL-*&lt;/code&gt; malicious-package advisories, and prompts for confirmation when a public package has a low download count.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block exotic transitive dependencies&lt;/strong&gt; — rejects transitive dependencies that resolve to &lt;code&gt;git+&lt;/code&gt;, &lt;code&gt;file:&lt;/code&gt;, or direct tarball URLs, which skip the registry and its integrity verification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a &lt;code&gt;paranoid: true&lt;/code&gt; switch that bundles all of the strict settings at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# aube-workspace.yaml&lt;/span&gt;
&lt;span class="na"&gt;paranoid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;allowBuilds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;esbuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;sharp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This forces jailed builds, no-downgrade trust policy, strict release-age gating, strict store integrity, strict dependency-build review, and mandatory advisory checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;The recommended installation path is &lt;a href="https://mise.en.dev/" rel="noopener noreferrer"&gt;Mise&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mise use &lt;span class="nt"&gt;-g&lt;/span&gt; aube
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also available via Homebrew (&lt;code&gt;brew install endevco/tap/aube&lt;/code&gt;) and npm (&lt;code&gt;npm install -g --ignore-scripts=false @endevco/aube&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Inside an existing Node.js project, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aubr &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aube will install dependencies if needed and then run the script. No migration step, no lockfile conversion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Daily commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aube add react          &lt;span class="c"&gt;# add a dependency&lt;/span&gt;
aube add &lt;span class="nt"&gt;-D&lt;/span&gt; vitest      &lt;span class="c"&gt;# add a dev dependency&lt;/span&gt;
aube remove react       &lt;span class="c"&gt;# remove a dependency&lt;/span&gt;
aube update             &lt;span class="c"&gt;# update within package.json ranges&lt;/span&gt;
aubr build              &lt;span class="c"&gt;# run a script, auto-installing if needed&lt;/span&gt;
aube &lt;span class="nb"&gt;test&lt;/span&gt;               &lt;span class="c"&gt;# run tests, auto-installing if needed&lt;/span&gt;
aubx cowsay hi          &lt;span class="c"&gt;# run a one-off tool&lt;/span&gt;
aube &lt;span class="nb"&gt;install&lt;/span&gt;            &lt;span class="c"&gt;# install only (setup, Docker, CI)&lt;/span&gt;
aube ci                 &lt;span class="c"&gt;# clean, frozen install for CI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also run scripts directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aube dev
aube build
aube lint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the script exists in &lt;code&gt;package.json&lt;/code&gt;, aube treats that as &lt;code&gt;aube run &amp;lt;script&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audit
&lt;/h2&gt;

&lt;p&gt;Aube has a built-in audit command that uses the same advisory data source as &lt;code&gt;npm audit&lt;/code&gt; and &lt;code&gt;pnpm audit&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aube audit                  &lt;span class="c"&gt;# list known CVEs at low+ severity&lt;/span&gt;
aube audit &lt;span class="nt"&gt;--audit-level&lt;/span&gt; high
aube audit &lt;span class="nt"&gt;--fix&lt;/span&gt;            &lt;span class="c"&gt;# write package.json overrides to patched versions&lt;/span&gt;
aube audit &lt;span class="nt"&gt;--json&lt;/span&gt; | jq      &lt;span class="c"&gt;# machine-readable for CI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to use it
&lt;/h2&gt;

&lt;p&gt;Aube is worth trying if you want faster installs without changing your team's workflow. The lockfile compatibility means you can use it locally while your CI and teammates continue with pnpm, npm, or Yarn. The security defaults are the most aggressive of any Node.js package manager I have seen, and &lt;code&gt;paranoid: true&lt;/code&gt; adds a lifecycle-script jail when you want the stricter bundle.&lt;/p&gt;

&lt;p&gt;The project is young (v1.x, MIT-licensed, &lt;a href="https://github.com/endevco/aube" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;) but moving fast. If you are already using Mise, the install is one command away.&lt;/p&gt;

</description>
      <category>node</category>
      <category>npm</category>
      <category>security</category>
    </item>
    <item>
      <title>Protecting your Node.js project against supply-chain attacks</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Sun, 17 May 2026 03:00:00 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/protecting-your-nodejs-project-against-supply-chain-attacks-5984</link>
      <guid>https://dev.to/douglasdemoura/protecting-your-nodejs-project-against-supply-chain-attacks-5984</guid>
      <description>&lt;p&gt;Several recent supply-chain incidents have hit widely used npm packages. The &lt;a href="https://tanstack.com/blog/npm-supply-chain-compromise-postmortem" rel="noopener noreferrer"&gt;TanStack compromise&lt;/a&gt;, for example, affected 42 packages and 84 published versions in May 2026. A few weeks earlier, the &lt;a href="https://www.microsoft.com/en-us/security/blog/2026/04/01/mitigating-the-axios-npm-supply-chain-compromise/" rel="noopener noreferrer"&gt;Axios compromise&lt;/a&gt; published malicious &lt;code&gt;axios@1.14.1&lt;/code&gt; and &lt;code&gt;axios@0.30.4&lt;/code&gt; releases.&lt;/p&gt;

&lt;p&gt;Many malicious releases are detected and removed within hours. Delaying dependency resolution gives the ecosystem time to catch bad versions before your project installs them. It is not a complete defense, but it is a small setting with a good payoff.&lt;/p&gt;

&lt;p&gt;npm 11.10+, Yarn 4.10+, and pnpm 10.16+ support release-age gates. pnpm 11 also sets a 24-hour cooldown by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  npm
&lt;/h2&gt;

&lt;p&gt;npm calls the setting &lt;code&gt;min-release-age&lt;/code&gt;, and the value is in days:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm config &lt;span class="nb"&gt;set &lt;/span&gt;min-release-age&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This writes &lt;code&gt;min-release-age=1&lt;/code&gt; to the project's &lt;code&gt;.npmrc&lt;/code&gt;. You can also use &lt;code&gt;--location=user&lt;/code&gt; or &lt;code&gt;--location=global&lt;/code&gt; to write to your user or global npm configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yarn (Berry 4.10+)
&lt;/h2&gt;

&lt;p&gt;Yarn calls the setting &lt;code&gt;npmMinimalAgeGate&lt;/code&gt;. In Yarn 4.10, use minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn config &lt;span class="nb"&gt;set &lt;/span&gt;npmMinimalAgeGate 1440
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This writes &lt;code&gt;npmMinimalAgeGate: 1440&lt;/code&gt; to the project's &lt;code&gt;.yarnrc.yml&lt;/code&gt;. Add &lt;code&gt;--home&lt;/code&gt; to write to &lt;code&gt;~/.yarnrc.yml&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;Current Yarn versions also accept duration strings, so this is equivalent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn config &lt;span class="nb"&gt;set &lt;/span&gt;npmMinimalAgeGate 1d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  pnpm
&lt;/h2&gt;

&lt;p&gt;pnpm calls the setting &lt;code&gt;minimumReleaseAge&lt;/code&gt;, and the value is in minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;project minimumReleaseAge 1440
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This writes &lt;code&gt;minimumReleaseAge: 1440&lt;/code&gt; to &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt;. Use &lt;code&gt;--location=global&lt;/code&gt; if you want to write to the global pnpm configuration instead.&lt;/p&gt;

&lt;p&gt;If you are already on pnpm 11, this is the default. Setting it explicitly can still be useful because it documents the policy in the repository and keeps older pnpm 10.16+ installs protected.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note for Dependabot and Renovate users
&lt;/h2&gt;

&lt;p&gt;The package-manager settings above are enforced when dependencies are installed or resolved. Dependency update bots make their own decisions before that point, so configure them too.&lt;/p&gt;

&lt;p&gt;For Dependabot, use &lt;code&gt;cooldown&lt;/code&gt; in &lt;code&gt;dependabot.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cooldown&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default-days&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dependabot cooldowns apply to version updates, not security updates.&lt;/p&gt;

&lt;p&gt;For Renovate, set &lt;code&gt;minimumReleaseAge&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"minimumReleaseAge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1 day"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Renovate also bypasses &lt;code&gt;minimumReleaseAge&lt;/code&gt; for security updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  A word of caution
&lt;/h2&gt;

&lt;p&gt;Keep committing your lockfile and use deterministic installs in CI, such as &lt;code&gt;npm ci&lt;/code&gt;, &lt;code&gt;pnpm install --frozen-lockfile&lt;/code&gt;, or &lt;code&gt;yarn install --immutable&lt;/code&gt;. A release-age gate reduces the chance of pulling a brand-new malicious version, but it will not clean up a compromised lockfile or make an already-installed bad version safe.&lt;/p&gt;

</description>
      <category>node</category>
      <category>npm</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Managing your development environment with Mise (and understanding shims!)</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Sun, 03 May 2026 19:09:00 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/managing-your-development-environment-with-mise-and-understanding-shims-1b7h</link>
      <guid>https://dev.to/douglasdemoura/managing-your-development-environment-with-mise-and-understanding-shims-1b7h</guid>
      <description>&lt;p&gt;I have run into this scenario a lot: we start a new project with the latest version of a programming language, but still need to maintain a legacy application that uses an older version of the same language. Sometimes I am working on a project that uses the LTS version, but I want to experiment with the latest nightly release on the side. Pretty much every language has some kind of tool to handle this, like &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;nvm&lt;/a&gt;, &lt;a href="https://github.com/Schniz/fnm" rel="noopener noreferrer"&gt;fnm&lt;/a&gt;, &lt;a href="https://github.com/mklement0/n-install" rel="noopener noreferrer"&gt;n&lt;/a&gt;, or &lt;a href="https://volta.sh/" rel="noopener noreferrer"&gt;volta&lt;/a&gt; for Node.js, &lt;a href="https://github.com/pyenv/pyenv" rel="noopener noreferrer"&gt;pyenv&lt;/a&gt; for Python, &lt;a href="https://github.com/rbenv/rbenv" rel="noopener noreferrer"&gt;rbenv&lt;/a&gt; for Ruby, &lt;a href="https://github.com/go-nv/goenv" rel="noopener noreferrer"&gt;goenv&lt;/a&gt; for Go, and so on. There are also polyglot solutions, which work for several languages, like &lt;a href="https://asdf-vm.com/" rel="noopener noreferrer"&gt;ASDF&lt;/a&gt; and my favorite one, &lt;a href="https://mise.jdx.dev/" rel="noopener noreferrer"&gt;Mise&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tool
&lt;/h2&gt;

&lt;p&gt;Mise is a solo project by Jeff Dickey, a Dallas-based developer who maintains a bunch of open-source tools (check his &lt;a href="https://jdx.dev/" rel="noopener noreferrer"&gt;website&lt;/a&gt; to see what he is up to). Besides managing programming language versions, Mise can set up environment variables and run project-specific tasks with the configured tool versions. You are not bound to its conventions, either: if you want to keep using the version file your project already has, like &lt;code&gt;.nvmrc&lt;/code&gt; or &lt;code&gt;.node-version&lt;/code&gt; for Node.js, Mise will respect it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The inner workings
&lt;/h2&gt;

&lt;p&gt;In simple terms, Mise installs the binaries for the selected programming language and shims your calls to that language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a shim?&lt;/strong&gt;&lt;br&gt;
A shim is a small compatibility layer that intercepts a call, handles it directly, or redirects it somewhere else. You can think of it as a proxy.&lt;/p&gt;

&lt;p&gt;To get a glimpse of how this works, let's implement a very basic shim to manage Node.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  Linux and Bash
&lt;/h3&gt;

&lt;p&gt;First, download Node.js' standalone binaries &lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Use the &lt;code&gt;.tar.xz&lt;/code&gt; archives. Extract them and move the extracted directories to &lt;code&gt;~/.nodejs&lt;/code&gt;. This directory should now look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node-v24.15.0-linux-x64
node-v25.9.0-linux-x64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Bash example also works on macOS. The only meaningful difference is the platform suffix in the extracted Node.js directory and in the &lt;code&gt;binary_path&lt;/code&gt; line: use &lt;code&gt;darwin-arm64&lt;/code&gt; on Apple Silicon Macs or &lt;code&gt;darwin-x64&lt;/code&gt; on Intel Macs. For example:&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="nv"&gt;binary_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;/node-v&lt;/span&gt;&lt;span class="nv"&gt;$version&lt;/span&gt;&lt;span class="s2"&gt;-darwin-arm64/bin/node"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's create a directory for our tests: &lt;code&gt;mkdir ~/shim-example&lt;/code&gt;. Then, let's add a file that tells the shim which version of Node.js we want to use in that directory. Run:&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;echo&lt;/span&gt; &lt;span class="s2"&gt;"24.15.0"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ~/shim-example/.node-version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's create the Bash script that will select the Node.js version we want:&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;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="c"&gt;# Makes the script exit when: a command fails (-e), a variable is unset (-u), any command in a pipeline fails (-o pipefail)&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="c"&gt;# Set the directory where you will save all the Node.js binaries you want&lt;/span&gt;
&lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.nodejs"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; .node-version &lt;span class="o"&gt;]&lt;/span&gt;&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;"No Node.js version defined. Please create a .node-version file and write the desired version."&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Read the .node-version file to select the desired Node.js version&lt;/span&gt;
&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .node-version&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$version&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&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;"No Node.js version defined. Please write the desired version in .node-version."&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;/node-v&lt;/span&gt;&lt;span class="nv"&gt;$version&lt;/span&gt;&lt;span class="s2"&gt;-linux-x64/bin/node"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$binary_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&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;"Node.js &lt;/span&gt;&lt;span class="nv"&gt;$version&lt;/span&gt;&lt;span class="s2"&gt; is not installed at &lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;. Go to https://nodejs.org/en/download, download a standalone binary, and extract it into &lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$binary_path&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this Bash script as &lt;code&gt;node&lt;/code&gt;, then move it to &lt;code&gt;~/.local/bin&lt;/code&gt; and make it executable:&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.local/bin
&lt;span class="nb"&gt;mv &lt;/span&gt;node ~/.local/bin/node
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ~/.local/bin/node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This directory will probably already be on your &lt;code&gt;$PATH&lt;/code&gt;. You can 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;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;':'&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Fx&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.local/bin"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If nothing is returned, you should add this directory to your &lt;code&gt;$PATH&lt;/code&gt;. Make sure it appears before any other directory that contains a &lt;code&gt;node&lt;/code&gt; executable. To check if everything went well, run &lt;code&gt;command -v node&lt;/code&gt;. You should see the following output:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; node
/home/your-username/.local/bin/node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run &lt;code&gt;node --version&lt;/code&gt; inside the &lt;code&gt;~/shim-example&lt;/code&gt; directory. You should see &lt;code&gt;v24.15.0&lt;/code&gt;. Change the version in &lt;code&gt;.node-version&lt;/code&gt; to 25.9.0 (&lt;code&gt;echo "25.9.0" &amp;gt; .node-version&lt;/code&gt;) and run &lt;code&gt;node --version&lt;/code&gt; again. You should see the new Node.js version activated in that directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows and PowerShell
&lt;/h3&gt;

&lt;p&gt;On Windows, download the &lt;code&gt;.zip&lt;/code&gt; standalone binaries from the same Node.js download page. Extract them into &lt;code&gt;$HOME\.nodejs&lt;/code&gt;. That directory should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;node-v24.15.0-win-x64&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;node-v25.9.0-win-x64&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the test directory and &lt;code&gt;.node-version&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ItemType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;\shim-example"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;\shim-example\.node-version"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"24.15.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create this PowerShell shim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="bp"&gt;$Error&lt;/span&gt;&lt;span class="n"&gt;ActionPreference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stop"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$versionsDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Join-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".nodejs"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$versionFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Join-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".node-version"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-LiteralPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$versionFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PathType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Leaf&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Write-Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"No Node.js version defined. Please create a .node-version file and write the desired version."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-LiteralPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$versionFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$version&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Write-Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"No Node.js version defined. Please write the desired version in .node-version."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$versionDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Join-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$versionsDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node-v&lt;/span&gt;&lt;span class="nv"&gt;$version&lt;/span&gt;&lt;span class="s2"&gt;-win-x64"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$binaryPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Join-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$versionDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node.exe"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-LiteralPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$binaryPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PathType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Leaf&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;Write-Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Node.js &lt;/span&gt;&lt;span class="nv"&gt;$version&lt;/span&gt;&lt;span class="s2"&gt; is not installed at &lt;/span&gt;&lt;span class="nv"&gt;$versionsDir&lt;/span&gt;&lt;span class="s2"&gt;. Go to https://nodejs.org/en/download, download a standalone binary, and extract it into &lt;/span&gt;&lt;span class="nv"&gt;$versionsDir&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="kr"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$binaryPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$LASTEXITCODE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save it as &lt;code&gt;node.ps1&lt;/code&gt; in a directory that is on your PowerShell path. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ItemType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;\bin"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Move-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\node.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Destination&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;\bin\node.ps1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;$HOME\bin&lt;/code&gt; is not on your path yet, add it for your user. Put it before the existing path so this shim wins over any other Node.js installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$userPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;SetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;\bin;&lt;/span&gt;&lt;span class="nv"&gt;$userPath&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a new PowerShell session so it picks up the updated path. Then check that PowerShell finds the shim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, run &lt;code&gt;node --version&lt;/code&gt; inside &lt;code&gt;$HOME\shim-example&lt;/code&gt;. You should see &lt;code&gt;v24.15.0&lt;/code&gt;. Change the version in &lt;code&gt;.node-version&lt;/code&gt; to 25.9.0 (&lt;code&gt;Set-Content -Path .\.node-version -Value "25.9.0"&lt;/code&gt;) and run &lt;code&gt;node --version&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;Mise does all of this, and a little more, using Rust. This example should still give you a pretty good idea of how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing and configuring Mise
&lt;/h2&gt;

&lt;p&gt;There is a myriad of ways to install Mise, so I recommend going directly to its &lt;a href="https://mise.jdx.dev/getting-started.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. After installing and configuring Mise, install the tools you &lt;a href="https://mise.jdx.dev/core-tools.html" rel="noopener noreferrer"&gt;need&lt;/a&gt;. Personally, I do not use the Mise configuration file (&lt;code&gt;mise.toml&lt;/code&gt;) in the Node.js projects I work on, because some people on the team use different tooling. Instead, I add the Node.js version to &lt;code&gt;.node-version&lt;/code&gt;, which is supported by a large number of similar tools.&lt;/p&gt;

</description>
      <category>development</category>
      <category>devtool</category>
      <category>programming</category>
    </item>
    <item>
      <title>Introducing Alucard: a light theme for Omarchy</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Sun, 26 Apr 2026 13:28:20 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/introducing-alucard-a-light-theme-for-omarchy-5el3</link>
      <guid>https://dev.to/douglasdemoura/introducing-alucard-a-light-theme-for-omarchy-5el3</guid>
      <description>&lt;p&gt;Since January, I've been using my own light theme for &lt;a href="https://github.com/basecamp/omarchy" rel="noopener noreferrer"&gt;Omarchy&lt;/a&gt; (do you use Linux and don't know Omarchy yet? Go check it out!) and I forgot to make an official announcement! So, yes, this late post is an attempt to rectify this mistake.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alucard: a light theme for Omarchy (and the arch-enemy of Dracula)
&lt;/h2&gt;

&lt;p&gt;I'm a die hard fan of the &lt;a href="https://draculatheme.com/" rel="noopener noreferrer"&gt;Dracula theme&lt;/a&gt; and I have been using it for years. And, as you might have guessed, I've been using everything I could with a dark theme. But, I have moved to a new house, which is super illuminated by the sun throughout the day with massive windows and, using dark themes with so much natural light proved to be a difficult task. Omarchy (my Linux distro of choice) comes very well served of beautiful &lt;a href="https://learn.omacom.io/2/the-omarchy-manual/52/themes?search=theme" rel="noopener noreferrer"&gt;themes&lt;/a&gt; and I started to use either Flexoki Light or Catppuccin Latte during the day. Yet, neither were quite my taste and I knew there were already a light version of the Dracula theme called Alucard that was offered by their Pro package. When I went to their website to check it out, I found out a quite complete &lt;a href="https://draculatheme.com/spec" rel="noopener noreferrer"&gt;specification&lt;/a&gt; for the Dracula and the Alucard theme, so, I did what any developer who loves open source do: I scratched my own itch, I mean, I started working on the Alucard theme for Omarchy and I have been using it everyday since January.&lt;/p&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%2F9iu51h7g8bvbkjtdn2rp.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%2F9iu51h7g8bvbkjtdn2rp.png" alt="Screenshot of the Alucard theme on Omarchy with the output of ls on the top left, nvim with Lazyvim opened on the bottom left and btop running on the right" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The road to get everything working beautifully
&lt;/h2&gt;

&lt;p&gt;When I started digging into the specification and building the theme, I found out a lot of applications (Alacritty, btop, Chromium, Ghostty, and Kitty) didn't had official Alucard themes, so I started building them myself (I yet have to create single repositories for them and open a PR to the Dracula team, I'll be doing it shortly). It took a few iterations for me to get satisfied with the color combinations, but everything worked beautifully.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wallpapers
&lt;/h2&gt;

&lt;p&gt;Currenttly, the theme is distributed with three wallpapers: Dracula Waves, Dracula Mountain, and Dracula Galaxy, all of which were taken from the official &lt;a href="https://github.com/dracula/wallpaper" rel="noopener noreferrer"&gt;Dracula wallpapers&lt;/a&gt; repository. I simply love the Dracula Waves walppaper and that's why it's the first choice when you install the theme.&lt;/p&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%2Fzvyb95e6q8o0q8op9uo0.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%2Fzvyb95e6q8o0q8op9uo0.png" alt="Dracula Waves Wallpaper" width="800" height="335"&gt;&lt;/a&gt;&lt;br&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%2Fd3f3onc4ty2gq9ce2qb7.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%2Fd3f3onc4ty2gq9ce2qb7.png" alt="Dracula Mountains Wallpaper" width="800" height="335"&gt;&lt;/a&gt;&lt;br&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%2Ffpvkfbiog6jdbm09z2qk.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%2Ffpvkfbiog6jdbm09z2qk.png" alt="Dracula Galaxy Wallpaper" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The repository
&lt;/h2&gt;

&lt;p&gt;All the code is available at &lt;a href="https://github.com/DouglasdeMoura/omarchy-alucard-theme" rel="noopener noreferrer"&gt;douglasdemoura/omarchy-alucard-theme&lt;/a&gt;. Feel free to send your feedback and contributions to make it event better.&lt;/p&gt;
&lt;h2&gt;
  
  
  The installation
&lt;/h2&gt;

&lt;p&gt;If you are using Omarchy, you can install the Alucard theme with the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omarchy-theme-install https://github.com/douglasdemoura/omarchy-alucard-theme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>linux</category>
      <category>omarchy</category>
      <category>themes</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Fri, 05 Dec 2025 23:48:46 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/-2ie3</link>
      <guid>https://dev.to/douglasdemoura/-2ie3</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0" class="crayons-story__hidden-navigation-link"&gt;How I made BeeThreads and what doest it solve&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/samsantosb" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1073001%2F375cd36f-421a-477c-a8c2-eef450c302d2.jpg" alt="samsantosb profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/samsantosb" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Sam
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Sam
                
              
              &lt;div id="story-author-preview-content-3087184" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/samsantosb" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1073001%2F375cd36f-421a-477c-a8c2-eef450c302d2.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Sam&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 5 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0" id="article-link-3087184"&gt;
          How I made BeeThreads and what doest it solve
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/node"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;node&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;6&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/samsantosb/how-i-made-beethreads-and-what-doest-it-solve-2fk0#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>showdev</category>
      <category>node</category>
      <category>performance</category>
    </item>
    <item>
      <title>Validate your environment variables with Zod</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Fri, 16 Aug 2024 03:00:00 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/validate-your-environment-variables-with-zod-2gna</link>
      <guid>https://dev.to/douglasdemoura/validate-your-environment-variables-with-zod-2gna</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;Zod&lt;/a&gt; is the most famous validation library in the TypeScript ecosystem. With Zod, you create a &lt;em&gt;schema&lt;/em&gt; and validate your data according to the schema. Observe the schema below:&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;z&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;zod&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;UserSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;coerce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&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;This schema can be used to validate an object as follows:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john@example.com&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="c1"&gt;// If there is a validation error, it throws an error&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validatedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// If there is a validation error, it returns an error object for you to handle later&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;safeValidatedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeParse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; { success: false; error: ZodError }&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; { success: true; data: 'billie' }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zod is capable of performing various types of validations on your data, so be sure to read the &lt;a href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validating Environment Variables
&lt;/h2&gt;

&lt;p&gt;We can use Zod to validate the values present in &lt;a href="https://nodejs.org/api/process.html#processenv" rel="noopener noreferrer"&gt;&lt;code&gt;process.env&lt;/code&gt;&lt;/a&gt; and even process them before using the environment variables in our application. Usually, I like to create an &lt;code&gt;environment.ts&lt;/code&gt; file, as in the example below:&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;z&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;zod&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;environmentSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// Define the possible values for NODE_ENV, always leaving a default value:&lt;/span&gt;
  &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="c1"&gt;// Environment variables are always defined as strings. Here, convert the string to a number and set a default value:&lt;/span&gt;
  &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;coerce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;default&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="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;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;environmentSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, just import the variable and use it throughout my application:&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="nx"&gt;Fastify&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;fastify&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;env&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;./environment.js&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="nc"&gt;Fastify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;listen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&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;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>typescript</category>
      <category>zod</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Using TypeScript in Node.js projects</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Mon, 08 Jul 2024 09:46:58 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/using-typescript-in-nodejs-projects-34he</link>
      <guid>https://dev.to/douglasdemoura/using-typescript-in-nodejs-projects-34he</guid>
      <description>&lt;p&gt;&lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; is tremendously helpful while developing Node.js applications. Let's see how to configure it for a seamless development experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up TypeScript
&lt;/h2&gt;

&lt;p&gt;First, we need to install TypeScript. We can do this by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to create a &lt;code&gt;tsconfig.json&lt;/code&gt; file in the root of our project. This file will contain the TypeScript configuration for our project. Here is an example of a &lt;code&gt;tsconfig.json&lt;/code&gt; file that I picked from &lt;a href="https://www.totaltypescript.com/tsconfig-cheat-sheet" rel="noopener noreferrer"&gt;Total TypeScript&lt;/a&gt; and added a few more things (read the code and pay attention to the comments):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Options:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"esModuleInterop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"es2022"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowJs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resolveJsonModule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"moduleDetection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"force"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isolatedModules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"verbatimModuleSyntax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Setting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;src/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"~/*"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Strictness&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noUncheckedIndexedAccess"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noImplicitOverride"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;transpiling&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TypeScript:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NodeNext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sourceMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;you're&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;building&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;library:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"declaration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;you're&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;building&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;library&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;monorepo:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"composite"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"declarationMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;transpiling&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TypeScript:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"preserve"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noEmit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;runs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DOM:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lib"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"es2022"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dom.iterable"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;doesn't&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DOM:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lib"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"es2022"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;I'm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;considering&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;src/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/**/*.ts"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up the build script
&lt;/h2&gt;

&lt;p&gt;Next, we need to set up a build script that will compile our TypeScript code to JavaScript. First, install &lt;a href="https://www.npmjs.com/package/tsc-alias" rel="noopener noreferrer"&gt;&lt;code&gt;tsc-alias&lt;/code&gt;&lt;/a&gt; to handle the aliases we defined in the &lt;code&gt;tsconfig.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; tsc-alias
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can add the &lt;code&gt;build&lt;/code&gt; script by adding the following script to our &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc &amp;amp;&amp;amp; tsc-alias"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up the development script
&lt;/h2&gt;

&lt;p&gt;Next, we need to set up a development script that will watch for changes in our TypeScript files and recompile them. Personally, I like to use &lt;a href="https://tsx.is/" rel="noopener noreferrer"&gt;&lt;code&gt;tsx&lt;/code&gt;&lt;/a&gt;, as it provides a much faster development experience compared to the built-in &lt;a href="https://www.typescriptlang.org/docs/handbook/configuring-watch.html" rel="noopener noreferrer"&gt;TypeScript watcher&lt;/a&gt; or &lt;a href="https://typestrong.org/ts-node/" rel="noopener noreferrer"&gt;ts-node&lt;/a&gt;. First, install &lt;code&gt;tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can add the &lt;code&gt;dev&lt;/code&gt; script (in order to start the project in development mode) by adding the following script to your &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc &amp;amp;&amp;amp; tsc-alias"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node --import=tsx --watch ./src/index.ts"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, you won't get typechecks while developing using &lt;code&gt;tsx&lt;/code&gt;, but you can run &lt;code&gt;npm run build&lt;/code&gt; for that or add a new &lt;code&gt;typecheck&lt;/code&gt; scripts to your &lt;code&gt;package.json&lt;/code&gt;, and run it whenever you want to check for type errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc &amp;amp;&amp;amp; tsc-alias"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node --import=tsx --watch ./src/index.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typecheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc --noEmit"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>The Powerful Programmer</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Tue, 23 Jan 2024 13:31:11 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/the-powerful-programmer-2db2</link>
      <guid>https://dev.to/douglasdemoura/the-powerful-programmer-2db2</guid>
      <description>&lt;p&gt;Estimating, implementing, and deploying software rapidly is a characteristic of powerful programmers, as &lt;a href="https://www.kentbeck.com/" rel="noopener noreferrer"&gt;Kent Beck&lt;/a&gt; mentions in his book &lt;a href="https://www.oreilly.com/library/view/extreme-programming-explained/0201616416/" rel="noopener noreferrer"&gt;Extreme Programming Explained&lt;/a&gt;. In this article, I will explore these three points, inserting my own opinions on each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estimation
&lt;/h2&gt;

&lt;p&gt;Estimating a software project is &lt;a href="https://jacobian.org/2021/may/20/estimation/" rel="noopener noreferrer"&gt;difficult&lt;/a&gt;, and there are various different techniques on how to estimate a software project. You can create a method, through your own experience, learn the method used by other companies but, you must pay attention that the central point is that you have a good idea of how much time the project will take. Projects have a beginning, middle, and end. Learn to estimate your work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;For me, particularly, implementing is the most fun part of the project. And as with any job, we have to be pragmatic in the choice of language and tools. Being pragmatic in the choice does not necessarily mean using the same as everyone else, because, often, some tools continue to be strong in the market due to pure inertia. &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt; is a good example of this. Besides there being many better options with better support (like &lt;a href="https://fastify.dev/" rel="noopener noreferrer"&gt;Fastify&lt;/a&gt;), many teams still start new projects with Express, even if it is not being maintained regularly, does not handle Promise rejections, etc.&lt;/p&gt;

&lt;p&gt;Besides the issue of tool choice, it is necessary that you &lt;strong&gt;master&lt;/strong&gt; the technology stack of your project, being able to implement the best solutions in the shortest possible time. At the tip of your tongue, you have to know a good pattern to apply in the project, a good backend framework, a good frontend framework or even a good full-stack framework. And the experience of development cannot be left out. For the implementation to be fast, the understanding of the project must be easy, its documentation adequate, and its tests need to validate the &lt;strong&gt;intention&lt;/strong&gt; flows of the user who will use the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;Today, can you build an entire project and put it into production, by yourself? And I'm not talking about uploading your project to a completely managed platform, like Vercel, but rather, about taking a Linux machine, installing the necessary tools, and exposing your application to the web. And no, this is not any kind of purism. If you are not a startup that can burn a few million reais per year, without worrying about the cost of your infrastructure, you should, at least, know how to start your application and keep it active between server restarts (preferably using containers), put it behind a reverse proxy (like &lt;a href="https://www.nginx.com/" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt; or &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddy&lt;/a&gt;), configure a firewall, and make a backup of the database in three different places. You can still bring up multiple instances of your application and use the same proxy tool as a load balancer to distribute your application's access to the different instances that are running.&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>projectpatterns</category>
      <category>career</category>
    </item>
    <item>
      <title>Generating MD5 hashes on Node.js</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Tue, 23 Jan 2024 13:28:34 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/generating-md5-strings-on-nodejs-4g1k</link>
      <guid>https://dev.to/douglasdemoura/generating-md5-strings-on-nodejs-4g1k</guid>
      <description>&lt;p&gt;You can create hashes in Node.js without the need to install any external library. Usually, I create the following utility function in the projects I work on:&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="cm"&gt;/**
 * Hashes a string using md5
 *
 * @param {string} str
 * @returns {string}
 */&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;md5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;md5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I use it to replace the &lt;a href="https://www.npmjs.com/package/md5" rel="noopener noreferrer"&gt;md5&lt;/a&gt; library whenever I come across it.&lt;/p&gt;

&lt;p&gt;Note that you can create hashes for any algorithm supported by the OpenSSL version on your platform. On Linux and Mac, you can see which algorithms are available with the command &lt;code&gt;openssl list -digest-algorithms&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Finding the greatest common divisor in TypeScript</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Sat, 13 Jan 2024 04:00:00 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/finding-the-greatest-common-divisor-in-typescript-2i3</link>
      <guid>https://dev.to/douglasdemoura/finding-the-greatest-common-divisor-in-typescript-2i3</guid>
      <description>&lt;p&gt;First described in the classic geometry book &lt;em&gt;Elements&lt;/em&gt;, by the ancient Greek mathematician Euclid (ca. 300 BC, at the book VII, proposition 2), the method of finding de greatest common divisor between the positive numbers &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt;, being &lt;em&gt;a &amp;gt; b&lt;/em&gt; consists on the knowledge that the common divisors of &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt; are the same of &lt;em&gt;a - b&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt;. Therefore, we can find this greatest common divisor by replacing the largest number (&lt;em&gt;a&lt;/em&gt;) by the different between the two numbers (&lt;em&gt;a - b&lt;/em&gt;), repeatedly, until the two numbers are equal. In TypeScript, we can do that like this:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gcd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&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="nx"&gt;b&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="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// When `a` is equal to `b`, return the result&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;b&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="nx"&gt;a&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// When `a` is bigger than b, calculate the the GCD again&lt;/span&gt;
  &lt;span class="c1"&gt;// with the new `a` being `a - b`.&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&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="nf"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// If the new `b` is bigger than `a`,&lt;/span&gt;
  &lt;span class="c1"&gt;// subtract a from it.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&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;This method can be very slow if the difference between &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt; is too large. Thankfully, there's another method to find the greatest common divisor between two numbers, that can be described as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In order to find the greatest common divisor between &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt;, being &lt;em&gt;a &amp;gt; b&lt;/em&gt;, perform the division between the two numbers. This operation will give a quotient and a remainder (that we will call &lt;em&gt;q&lt;/em&gt; and &lt;em&gt;r&lt;/em&gt;, respectively). Thus, &lt;em&gt;a&lt;/em&gt; can be described as &lt;em&gt;a = q × b + r&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt; If &lt;em&gt;r&lt;/em&gt; is equal to 0, we stop, because we found that the greatest common divisor of &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;b&lt;/em&gt; is &lt;em&gt;b&lt;/em&gt;. Otherwise, we go back to step 1, making &lt;em&gt;b&lt;/em&gt; the new &lt;em&gt;a&lt;/em&gt; and &lt;em&gt;r&lt;/em&gt; will be the new &lt;em&gt;b&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, we can start with the implementation of the algorithm above:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gcd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&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="nx"&gt;b&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="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// First, we take the remainder between the division of a and b:&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;

  &lt;span class="c1"&gt;// If the remainder is equal to zero, it means that we already found the&lt;/span&gt;
  &lt;span class="c1"&gt;// greatest common divisor, therefore, we return b:&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&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="nx"&gt;b&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// If the remainder is not equal to 0, we call the function again&lt;/span&gt;
  &lt;span class="c1"&gt;// with the new values for a and b:&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;b&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;The implementation is very straightforward and can be read exactly as is described in steps 1 and 2. We can make the function simpler, by checking, directly, if &lt;em&gt;b&lt;/em&gt; is equal to zero and only doing the remainder operation afterwards. Therefore, if the function receive a &lt;em&gt;b&lt;/em&gt; that is equal to zero, we will know that &lt;em&gt;a&lt;/em&gt; is the greatest common divisor:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gcd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&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="nx"&gt;b&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="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&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="nx"&gt;a&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;b&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;This variant is called &lt;em&gt;Euclidean algorithm&lt;/em&gt; (in contrast of the first one, which is the &lt;em&gt;Euclid's algorithm&lt;/em&gt;) and it significantly faster than the first implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative implementations
&lt;/h2&gt;

&lt;p&gt;We can also take a different approach. Instead of calling our &lt;code&gt;gcd&lt;/code&gt; function recursively, we can implement our function using a &lt;code&gt;while&lt;/code&gt; loop (analogous to our first implementation above):&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gcd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&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="nx"&gt;b&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="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Run this loop while a is different of b&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Subtracts b from a while a is bigger than b&lt;/span&gt;
      &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
      &lt;span class="c1"&gt;// Go to the next loop&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Subtracts a from b when a &amp;lt;= b&lt;/span&gt;
    &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Returns the greatest common divisor between a and b&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is another way (analogous to our second implementation above):&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gcd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&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="nx"&gt;b&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="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Run this loop while `b` is different from 0&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Save the new value for a in a temporary variable&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
    &lt;span class="c1"&gt;// Set b to the modulo of a and b (the remainder of the division between a and b)&lt;/span&gt;
    &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
    &lt;span class="c1"&gt;// Set a to its new value before the next loop&lt;/span&gt;
    &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newA&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Now that b is equal to 0, we know that a is the greatest common divisor&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Finding the greatest common between three or more numbers
&lt;/h2&gt;

&lt;p&gt;The greatest  of three or more numbers is equal the product of the prime factors common to all the numbers (we will explore more of that in a future article), but, you can also calculate the greatest common divisor between pairs of this list of numbers with the same functions we have showed already. So, let's refactor our &lt;code&gt;gcd&lt;/code&gt; function to receive multiple parameters:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gcd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;numbers&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="kr"&gt;number&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;calculateGcd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;a&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="na"&gt;b&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="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&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="nx"&gt;a&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;calculateGcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;b&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="nx"&gt;numbers&lt;/span&gt;
      &lt;span class="c1"&gt;// Just to be sure, sort numbers in descendant order:&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;// Call `calculateGcd` for each pair in the numbers array:&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;calculateGcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Validating our input
&lt;/h2&gt;

&lt;p&gt;Let's guarantee that our functions should always receive, at least, two numbers and that all numbers must not be negative:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gcd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;numbers&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="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You must pass, at least, 2 numbers&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The numbers must be &amp;gt;= 0&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;calculateGcd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;a&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="na"&gt;b&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="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&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="nx"&gt;a&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;calculateGcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;b&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="nx"&gt;numbers&lt;/span&gt;
      &lt;span class="c1"&gt;// Just to be sure, sort numbers in descendant order:&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;// Call `calculateGcd` for each pair in the numbers array:&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;calculateGcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>typescript</category>
      <category>mathematics</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Understanding Tail Call Optimization With JavaScript</title>
      <dc:creator>Douglas Moura</dc:creator>
      <pubDate>Wed, 25 Oct 2023 10:00:00 +0000</pubDate>
      <link>https://dev.to/douglasdemoura/understanding-tail-call-optimization-with-javascript-3da8</link>
      <guid>https://dev.to/douglasdemoura/understanding-tail-call-optimization-with-javascript-3da8</guid>
      <description>&lt;p&gt;Consider the following function that calculates the factorial of a number:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;
    &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function above was implemented iteratively, that is, it uses a loop to calculate the factorial of a number. However, it is possible to implement the same function recursively (that is, a function that references itself):&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&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;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&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;The result of both functions is the same, however, the iterative function is &lt;a href="https://jsben.ch/1qyl8" rel="noopener noreferrer"&gt;much more efficient&lt;/a&gt; (in JavaScript) than the recursive function. In addition, if we try to calculate the factorial of a very large number, we encounter the error RangeError: Maximum call stack size exceeded. Let's understand why this happens and how we can improve the recursive function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call Stack
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Call_stack" rel="noopener noreferrer"&gt;call stack&lt;/a&gt; is a data structure that stores information about a program's functions. When a function is called, it is added to the execution stack, as well as all the functions it calls. When a function returns, it is removed from the execution stack. Each function added to the stack is called a &lt;em&gt;stack frame&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In order to understand what is happening, let's try to represent, graphically, how the calculation of the factorial of 6 is done with the iterative function:&lt;/p&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%2Fercbjpvaqn55j27qkkpk.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%2Fercbjpvaqn55j27qkkpk.png" alt="Substitutive model of the iterative function" width="306" height="801"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, compare it with the substitution model for calculating the factorial of 6 using the recursive function:&lt;/p&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%2Fhtw2bnbezr8i7a034mnx.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%2Fhtw2bnbezr8i7a034mnx.png" alt="Substitutive model of the recursive function" width="544" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that, in the iterative function, the arrow shape is linear and we can see the state of each variable at each step. In addition, at each iteration of our loop, a calculation is performed and the variables stored in memory are updated. In the recursive function, the arrow shape is exponential and we cannot see the state of all variables in the first half of the processing. In addition, each time the function is executed, more memory needs to be used to store the resulting values of each execution.&lt;/p&gt;

&lt;p&gt;But what does this mean? In order for JavaScript to calculate the factorial of 6 using the iterative function, the &lt;code&gt;while&lt;/code&gt; condition is added to the stack, where its calculation is performed, the &lt;code&gt;result&lt;/code&gt; variable is updated, and then the executed code block of the &lt;code&gt;while&lt;/code&gt; is removed from the stack. This is done until the while condition is false, that is, until the value of &lt;code&gt;n&lt;/code&gt; is less than or equal to 1.&lt;/p&gt;

&lt;p&gt;In the recursive function, each call to the &lt;code&gt;factorial&lt;/code&gt; function is added to the stack as many times as necessary until the if condition is false, that is, until the value of &lt;code&gt;n&lt;/code&gt; is less than or equal to 1. This means that, to calculate the factorial of 6, the &lt;code&gt;factorial&lt;/code&gt; function is added to the stack 6 times before being executed. And that's why, when we try to calculate the factorial of a large number (100,000, for example), we encounter the error &lt;code&gt;RangeError: Maximum call stack size exceeded&lt;/code&gt;: there is not enough space in the stack to store all the calls to the &lt;code&gt;factorial&lt;/code&gt; function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Tail Call Optimization
&lt;/h2&gt;

&lt;p&gt;As defined by &lt;a href="https://dr-axel.de/" rel="noopener noreferrer"&gt;Dr. Axel Rauschmayer&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[...] whenever the last thing a function does is call another function, then this last function does not need to return to its caller. As a consequence, no information needs to be stored on the call stack and the function call is more like a goto (a jump). This type of call is called a &lt;em&gt;tail call&lt;/em&gt;; not increasing the stack is called tail call optimization (TCO).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, we have discovered that our factorial calculation function is not tail recursive. But how can we make it tail recursive? With the help of another function:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;factorialHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&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;factorialHelper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accumulator&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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="nx"&gt;accumulator&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;factorialHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;accumulator&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;Now, our function is tail recursive: the last thing it does is call a function (and not calculate an expression, as in the first implementation). Now, let's see the substitution model for calculating the factorial of 6 with our new &lt;code&gt;factorial&lt;/code&gt; function:&lt;/p&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%2Fht8ce9ign9t8862vqhrr.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%2Fht8ce9ign9t8862vqhrr.png" alt="Substitutive model of the new factorial function" width="347" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jsben.ch/vOf9P" rel="noopener noreferrer"&gt;The performance is superior&lt;/a&gt; to our first implementation, although it still doesn't beat the performance of the iterative function. However, we still encounter the error &lt;code&gt;RangeError: Maximum call stack size exceeded&lt;/code&gt;. But why does this happen? Because, despite our function being tail recursive, current versions of Node.js and browsers (&lt;a href="https://webkit.org/blog/6240/ecmascript-6-proper-tail-calls-in-webkit/" rel="noopener noreferrer"&gt;with the exception of Safari&lt;/a&gt;) do not implement Tail Call Optimization (despite its inclusion in the &lt;a href="https://262.ecma-international.org/6.0/#sec-tail-position-calls" rel="noopener noreferrer"&gt;EcmaScript&lt;/a&gt; specification since 2015).&lt;/p&gt;

&lt;p&gt;But how will we solve this problem? With the help of another function, of course! For that, we will rely on the &lt;a href="https://en.wikipedia.org/wiki/Trampoline_(computing)" rel="noopener noreferrer"&gt;Trampoline&lt;/a&gt; pattern:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trampoline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&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="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&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;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fn&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="nx"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our trampoline function consists of a loop that invokes a function that wraps another function (what we call a &lt;a href="https://en.wikipedia.org/wiki/Thunk" rel="noopener noreferrer"&gt;thunk&lt;/a&gt;) until there are no more functions to execute. Let's see how the implementation of our factorial function would look like with the Trampoline pattern:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trampoline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&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="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&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;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fn&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="nx"&gt;fn&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;factorialHelper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accumulator&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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="nx"&gt;accumulator&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Now, a function returns another function&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;gt;&lt;/span&gt; &lt;span class="nf"&gt;factorialHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;accumulator&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;factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorialHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&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;And now, we can call our factorial function with a large number, without encountering the error &lt;code&gt;RangeError: Maximum call stack size exceeded&lt;/code&gt;. Of course, depending on the factorial we want to calculate, we will encounter an Infinity, as it is a very large number (a number greater than Number.MAX_SAFE_INTEGER: 253 - &lt;sup&gt;1&lt;/sup&gt;). In this case, we can use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt" rel="noopener noreferrer"&gt;BigInt&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trampoline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&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="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&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;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fn&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="nx"&gt;fn&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;factorialHelper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accumulator&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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="nx"&gt;accumulator&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;gt;&lt;/span&gt; &lt;span class="nf"&gt;factorialHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;accumulator&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;factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="c1"&gt;// Converting values to BigInt&lt;/span&gt;
  &lt;span class="c1"&gt;//-------------------------------\/----------\/&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorialHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;n&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;h2&gt;
  
  
  Typing our function
&lt;/h2&gt;

&lt;p&gt;And finally, let's add the necessary types to our factorial function:&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Thunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt; &lt;span class="o"&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="nx"&gt;Thunk&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;trampoline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Thunk&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="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&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;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fn&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="nx"&gt;fn&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;factorialHelper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accumulator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Thunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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="nx"&gt;accumulator&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;gt;&lt;/span&gt; &lt;span class="nf"&gt;factorialHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;accumulator&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;factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;trampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;factorialHelper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;n&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;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.mgmarlow.com/words/2021-03-27-proper-tail-calls-js/" rel="noopener noreferrer"&gt;What happened to proper tail calls in JavaScript?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://exploringjs.com/es6/ch_tail-calls.html" rel="noopener noreferrer"&gt;Tail Call Optmization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://cangaceirojavascript.com.br/limites-recursao-javascript-tco-e-pattern-trampoline/" rel="noopener noreferrer"&gt;Limites da recursão em JavaScript, TCO e o pattern Trampoline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://softwareengineering.stackexchange.com/a/189973/383960" rel="noopener noreferrer"&gt;What is an Activation object in JavaScript?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mathworld.wolfram.com/Factorial.html" rel="noopener noreferrer"&gt;Factorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=_JtPhF8MshA" rel="noopener noreferrer"&gt;Tail Recursion Explained - Computerphile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=-PX0BV9hGZY" rel="noopener noreferrer"&gt;Tail Call Optimization: The Musical!!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>algorithms</category>
      <category>mathematics</category>
      <category>javascript</category>
      <category>node</category>
    </item>
  </channel>
</rss>
