<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Alessio Pelliccione</title>
    <description>The latest articles on Forem by Alessio Pelliccione (@alessiopelliccione).</description>
    <link>https://forem.com/alessiopelliccione</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3592575%2Fc764495c-4be7-4fb9-aa7e-b5840e4dd59e.jpg</url>
      <title>Forem: Alessio Pelliccione</title>
      <link>https://forem.com/alessiopelliccione</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alessiopelliccione"/>
    <language>en</language>
    <item>
      <title>How modern dev servers decide what to rebuild - a minimal engine</title>
      <dc:creator>Alessio Pelliccione</dc:creator>
      <pubDate>Sat, 01 Nov 2025 17:52:28 +0000</pubDate>
      <link>https://forem.com/alessiopelliccione/how-modern-dev-servers-decide-what-to-rebuild-a-minimal-engine-4ol</link>
      <guid>https://forem.com/alessiopelliccione/how-modern-dev-servers-decide-what-to-rebuild-a-minimal-engine-4ol</guid>
      <description>&lt;p&gt;&lt;em&gt;by Alessio Pelliccione&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some days ago, I was writing a small dynamic script to trigger a build for a single file. While doing that, I suddenly wondered: how do modern build tools actually work under the hood?&lt;/p&gt;

&lt;p&gt;That question led me to start building a minimal engine — something simple enough to grasp the core idea, but realistic enough to mirror how tools like &lt;strong&gt;esbuild&lt;/strong&gt; or &lt;strong&gt;Vite&lt;/strong&gt; handle rebuilds internally, deciding what to rebuild.&lt;/p&gt;

&lt;p&gt;Let’s see the process step by step — from file watching to dependency graph validation — to see what really happens when you hit “Save”.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s actually happening under the hood
&lt;/h2&gt;

&lt;p&gt;When you hit &lt;strong&gt;“Save”&lt;/strong&gt;, your dev server doesn’t rebuild the whole project.&lt;/p&gt;

&lt;p&gt;Instead, it follows a smart and very fast chain of steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The file watcher fires an event — tools like &lt;code&gt;chokidar&lt;/code&gt; detect which file changed.
&lt;/li&gt;
&lt;li&gt;The server looks up that file in its dependency graph — a map of who imports what.
&lt;/li&gt;
&lt;li&gt;It invalidates the module and all the modules that depend on it.
&lt;/li&gt;
&lt;li&gt;Only those affected modules are rebuilt and reloaded.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it — no full recompilation, no walking through the entire codebase.&lt;/p&gt;

&lt;p&gt;This is what makes tools like &lt;strong&gt;Vite&lt;/strong&gt; and &lt;strong&gt;esbuild&lt;/strong&gt; feel instant during development.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building a minimal smart rebuild engine (with TypeScript code)
&lt;/h2&gt;

&lt;p&gt;Let’s recreate the core idea behind the tools that I mentioned before — but in less than 40 lines of code. The requirements are simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;watch files
&lt;/li&gt;
&lt;li&gt;detect changes
&lt;/li&gt;
&lt;li&gt;compute their hashes
&lt;/li&gt;
&lt;li&gt;rebuild only what’s affected
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1 — Watch the filesystem
&lt;/h3&gt;

&lt;p&gt;We will use &lt;code&gt;chokidar&lt;/code&gt; to detect changes in the &lt;code&gt;src/&lt;/code&gt; directory:&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;chokidar&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;chokidar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;watcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chokidar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&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;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; File changed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&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;Every time you save a file, this watcher emits an event.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Cache file hashes
&lt;/h3&gt;

&lt;p&gt;We don’t want to rebuild if the content didn’t really change (auto‑formatting, whitespace edits). So let’s keep a hash map of file contents:&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;crypto&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;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&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;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&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;function&lt;/span&gt; &lt;span class="nf"&gt;hashFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf‑8&lt;/span&gt;&lt;span class="dl"&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;crypto&lt;/span&gt;&lt;span class="p"&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;sha1&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;content&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can compare the old and the new hash whenever a file changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Track dependencies
&lt;/h3&gt;

&lt;p&gt;We’ll store a simple dependency graph to know which files import which:&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;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// file → [importers]&lt;/span&gt;
&lt;span class="c1"&gt;// Example:&lt;/span&gt;
&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/utils/date.ts&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/app.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/app.ts&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/main.ts&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;This tells us that if &lt;code&gt;date.ts&lt;/code&gt; changes, &lt;code&gt;app.ts&lt;/code&gt; and then &lt;code&gt;main.ts&lt;/code&gt; should be invalidated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — Invalidate affected modules
&lt;/h3&gt;

&lt;p&gt;Here’s the rebuild logic — recursive invalidation of dependents:&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;function&lt;/span&gt; &lt;span class="nf"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;♻️ Rebuilding&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&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;dependents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;dependents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;invalidate&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 we connect everything:&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="nx"&gt;watcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&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;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newHash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hashFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;newHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it! You just built the heart of a smart rebuild engine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The real implementation in my repo is a bit more advanced: it keeps a full dependency graph, incremental cache, and diagnostics for rebuild chains.&lt;br&gt;&lt;br&gt;
You can explore it here: &lt;a href="https://github.com/alessiopelliccione/reboost" rel="noopener noreferrer"&gt;https://github.com/alessiopelliccione/reboost&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Understanding HMR (Hot Module Replacement) propagation
&lt;/h2&gt;

&lt;p&gt;Now that our minimal engine knows which modules to rebuild, the next question is: how does the browser update so fast — without a full reload?&lt;/p&gt;

&lt;h3&gt;
  
  
  The idea
&lt;/h3&gt;

&lt;p&gt;Instead of refreshing the entire page, HMR lets the browser replace only the affected module at runtime. Think of it like a “live patch” system for JavaScript.&lt;/p&gt;

&lt;p&gt;When a file changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The dev server detects it (our watcher)
&lt;/li&gt;
&lt;li&gt;It invalidates the affected modules
&lt;/li&gt;
&lt;li&gt;It sends a WebSocket message to the browser
&lt;/li&gt;
&lt;li&gt;The browser dynamically imports the new module
&lt;/li&gt;
&lt;li&gt;If the module accepts the update, it’s replaced in place — no full reload
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  How it connects back to Reboost
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://github.com/alessiopelliccione/reboost" rel="noopener noreferrer"&gt;Reboost&lt;/a&gt;, this concept becomes even more transparent: each module knows who depends on it through the dependency graph, and when a file changes, the invalidation chain determines how far the rebuild should go before notifying the browser.&lt;/p&gt;




&lt;h2&gt;
  
  
  Beyond this article
&lt;/h2&gt;

&lt;p&gt;This post only scratches the surface.&lt;/p&gt;

&lt;p&gt;My project &lt;strong&gt;Reboost&lt;/strong&gt; is a small experimental engine that goes a step further. It’s not meant to replace modern dev servers, but to understand how they work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/alessiopelliccione/reboost" rel="noopener noreferrer"&gt;https://github.com/alessiopelliccione/reboost&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Topics: &lt;code&gt;#vite&lt;/code&gt; &lt;code&gt;#esbuild&lt;/code&gt; &lt;code&gt;#hmr&lt;/code&gt; &lt;code&gt;#javascript&lt;/code&gt; &lt;code&gt;#bundler&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Related: &lt;a href="https://vitejs.dev" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; · &lt;a href="https://esbuild.github.io" rel="noopener noreferrer"&gt;Esbuild&lt;/a&gt; · &lt;a href="https://webpack.js.org/concepts/hot-module-replacement/" rel="noopener noreferrer"&gt;HMR&lt;/a&gt; · &lt;a href="https://en.wikipedia.org/wiki/JavaScript_bundler" rel="noopener noreferrer"&gt;JavaScript bundlers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written by Alessio Pelliccione&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>javascript</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
