<?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: Trường Nguyễn</title>
    <description>The latest articles on DEV Community by Trường Nguyễn (@htruong354).</description>
    <link>https://dev.to/htruong354</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%2F4197202%2Fb5485346-7c6e-4382-804b-3c6961ae1204.png</url>
      <title>DEV Community: Trường Nguyễn</title>
      <link>https://dev.to/htruong354</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/htruong354"/>
    <language>en</language>
    <item>
      <title>I rewrote VS Code's Live Server in Rust: one 3 MB binary, no Node.js</title>
      <dc:creator>Trường Nguyễn</dc:creator>
      <pubDate>Wed, 21 Oct 2026 11:26:13 +0000</pubDate>
      <link>https://dev.to/htruong354/i-rewrote-vs-codes-live-server-in-rust-one-3-mb-binary-no-nodejs-267n</link>
      <guid>https://dev.to/htruong354/i-rewrote-vs-codes-live-server-in-rust-one-3-mb-binary-no-nodejs-267n</guid>
      <description>&lt;p&gt;I like VS Code's Live Server: click &lt;strong&gt;Go Live&lt;/strong&gt;, the page opens, save a file and it reloads. What I didn't like was everything behind it: a Node.js process, a &lt;code&gt;node_modules&lt;/code&gt; tree, and about 230 MB of memory to serve a few HTML files.&lt;/p&gt;

&lt;p&gt;So I rewrote it in Rust. &lt;strong&gt;live-serve&lt;/strong&gt; is a single binary of about 3 MB that serves a folder, reloads the page when a file changes, and swaps stylesheets in place without reloading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzm0x7biod7kbuwqccoxk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzm0x7biod7kbuwqccoxk.gif" alt="Saving style.css swaps the stylesheet without a reload; saving index.html reloads the page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install nguyentruong354/tap/live-serve   # macOS, Linux
scoop install live-serve                      # Windows (after: scoop bucket add nguyentruong354 https://github.com/NguyenTruong354/scoop-bucket)
cargo install live-serve                      # anywhere with Rust

live-serve --open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In VS Code, install the extension &lt;strong&gt;live-serve-rs&lt;/strong&gt; (also on Open VSX for VSCodium, Cursor and Windsurf). It bundles the binary, so nothing else needs installing; click &lt;strong&gt;Go Live&lt;/strong&gt; in the status bar.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Live reload over a WebSocket; saving a stylesheet swaps only the sheets from your own origin&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--https&lt;/code&gt; with a self-signed certificate made on the fly, or &lt;code&gt;--cert&lt;/code&gt;/&lt;code&gt;--key&lt;/code&gt; for one from mkcert&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--proxy /api=http://localhost:3000&lt;/code&gt; so a static frontend can call a local backend without CORS&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--spa&lt;/code&gt; for single-page apps, &lt;code&gt;--host 0.0.0.0&lt;/code&gt; to open it on your phone&lt;/li&gt;
&lt;li&gt;Refuses requests from other websites (DNS rebinding, cross-origin reads) and hides &lt;code&gt;.env&lt;/code&gt; and &lt;code&gt;.git&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;live-serve init vscode&lt;/code&gt; / &lt;code&gt;init zed&lt;/code&gt; adds an editor task to the project&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Numbers
&lt;/h2&gt;

&lt;p&gt;Against &lt;code&gt;live-server&lt;/code&gt;, the package VS Code's Live Server runs, on the same machine and folder (median of six rounds; &lt;a href="https://github.com/NguyenTruong354/live-serve/blob/main/BENCHMARKS.md" rel="noopener noreferrer"&gt;method&lt;/a&gt;):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;live-serve&lt;/th&gt;
&lt;th&gt;live-server&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Folder listing, 1,200 entries&lt;/td&gt;
&lt;td&gt;2.0 ms&lt;/td&gt;
&lt;td&gt;~48 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML page with the reload script&lt;/td&gt;
&lt;td&gt;0.50 ms&lt;/td&gt;
&lt;td&gt;0.7–1.5 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First response after start&lt;/td&gt;
&lt;td&gt;44 ms&lt;/td&gt;
&lt;td&gt;~1.4 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory&lt;/td&gt;
&lt;td&gt;11 MB&lt;/td&gt;
&lt;td&gt;~230 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Static files cost about the same for both: reading the file and the loopback connection dominate. The difference is everything around the files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that were harder than they looked
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The watch dies with the folder.&lt;/strong&gt; Build tools love &lt;code&gt;rm -rf dist &amp;amp;&amp;amp; build&lt;/code&gt;. A file watcher on &lt;code&gt;dist&lt;/code&gt; stops when &lt;code&gt;dist&lt;/code&gt; is deleted, so after the first rebuild nothing reloads anymore. live-serve also watches the parent folder and re-arms the watch when the folder comes back. macOS made this fun: FSEvents can report the folder's &lt;em&gt;creation&lt;/em&gt; late, after the removal, so "created" alone can't mean "it's back".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two programs on one port.&lt;/strong&gt; On Windows and macOS, one program can listen on &lt;code&gt;0.0.0.0:5500&lt;/code&gt; while another binds &lt;code&gt;127.0.0.1:5500&lt;/code&gt;, and both succeed. live-serve used to "take" localhost away from a server that was already running. It now checks the other kind of address before binding and moves to the next port.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTPS without setup.&lt;/strong&gt; &lt;code&gt;--https&lt;/code&gt; makes an ECDSA certificate with rcgen for &lt;code&gt;localhost&lt;/code&gt;, &lt;code&gt;127.0.0.1&lt;/code&gt;, &lt;code&gt;::1&lt;/code&gt; and, with &lt;code&gt;--host 0.0.0.0&lt;/code&gt;, your network address, keeps it in a cache folder and renews it before it expires. TLS is rustls with ring, which added about 1.2 MB to the binary. A plain &lt;code&gt;http://&lt;/code&gt; request to the HTTPS port gets a redirect instead of a confusing error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS swaps and editors.&lt;/strong&gt; Many editors save by writing a temporary file and renaming it. The reload script has to recognise that the stylesheet changed (not that some random &lt;code&gt;.tmp&lt;/code&gt; appeared) and swap only the sheets from the page's own origin, so a stylesheet from a CDN or Google Fonts isn't fetched again on every save.&lt;/p&gt;

&lt;p&gt;It's built on axum, tokio and notify.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it was built
&lt;/h2&gt;

&lt;p&gt;I wrote the core myself and used Claude (an AI assistant) for parts of the HTTPS, proxy and file-watching work, the tests and the release pipeline. I reviewed every change before merging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback welcome
&lt;/h2&gt;

&lt;p&gt;The code is MIT-licensed on GitHub: &lt;strong&gt;&lt;a href="https://github.com/NguyenTruong354/live-serve" rel="noopener noreferrer"&gt;https://github.com/NguyenTruong354/live-serve&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd especially like to hear how the file watching behaves with your build tool, and whether the HTTPS setup works on your machine. Issues and PRs are welcome.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>rust</category>
      <category>webdev</category>
      <category>vscode</category>
    </item>
  </channel>
</rss>
