<?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: 阿豪</title>
    <description>The latest articles on Forem by 阿豪 (@ahaoboy).</description>
    <link>https://forem.com/ahaoboy</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%2F477097%2F52ce6425-c7cd-48c0-b803-c8fa0547f6b0.png</url>
      <title>Forem: 阿豪</title>
      <link>https://forem.com/ahaoboy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ahaoboy"/>
    <language>en</language>
    <item>
      <title>ytdlp-jsc: A JS Challenge Solver Without Runtime Dependencies</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Fri, 05 Dec 2025 14:25:59 +0000</pubDate>
      <link>https://forem.com/ahaoboy/ytdlp-jsc-a-js-challenge-solver-without-runtime-dependencies-3ag3</link>
      <guid>https://forem.com/ahaoboy/ytdlp-jsc-a-js-challenge-solver-without-runtime-dependencies-3ag3</guid>
      <description>&lt;p&gt;&lt;strong&gt;ytdlp-jsc&lt;/strong&gt; is a yt-dlp plugin that solves YouTube's JavaScript challenges without requiring external JS runtimes like Node.js or Deno.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/ahaoboy/ytdlp-jsc" rel="noopener noreferrer"&gt;ahaoboy/ytdlp-jsc&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;ytdlp-jsc &lt;span class="nt"&gt;--target&lt;/span&gt; ~/.yt-dlp/plugins/
yt-dlp &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"https://www.youtube.com/watch?v=BnnbP7pCIvQ"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[youtube] BnnbP7pCIvQ: Downloading player c816c7d8-main
[youtube] [jsc:ytdlp-jsc] Solving JS challenges using ytdlp-jsc
[info] Available formats for BnnbP7pCIvQ:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Not Just Use a JS Runtime?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Runtime vs Engine
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Capabilities&lt;/th&gt;
&lt;th&gt;Security&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Runtime&lt;/strong&gt; (Node, Deno)&lt;/td&gt;
&lt;td&gt;Full system access: file I/O, network, shell&lt;/td&gt;
&lt;td&gt;Higher risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Engine&lt;/strong&gt; (QuickJS)&lt;/td&gt;
&lt;td&gt;JS execution only&lt;/td&gt;
&lt;td&gt;Sandboxed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ytdlp-jsc embeds a lightweight JS engine — no system access, no security concerns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Startup Time Matters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deno a.js    → 400ms
qjs a.js     → 27ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deno is safe but slow to start. For a single challenge solve:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Breakdown&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;External runtime&lt;/td&gt;
&lt;td&gt;CLI start (200ms) + parse (50ms) + codegen (50ms) + run (50ms)&lt;/td&gt;
&lt;td&gt;~350ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ytdlp-jsc (SWC + QJS)&lt;/td&gt;
&lt;td&gt;Load .pyd (50ms) + parse (100ms) + codegen (100ms) + run (100ms)&lt;/td&gt;
&lt;td&gt;~350ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Despite using a slower engine, ytdlp-jsc matches runtime performance by eliminating CLI startup overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmarks
&lt;/h2&gt;

&lt;p&gt;Tested on GitHub CI (~5MB binary):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ejs --runtime qjs     1.00x (baseline)
node                  1.35x slower
ytdlp-jsc             1.44x slower
ytdlp-jsc-cli         1.54x slower
bun                   1.56x slower
deno                  1.59x slower
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ytdlp</category>
      <category>deno</category>
      <category>quickjs</category>
      <category>ytdlpjsc</category>
    </item>
    <item>
      <title>Improving yt-dlp-ejs with Rust: Smaller and Faster</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Tue, 02 Dec 2025 13:26:51 +0000</pubDate>
      <link>https://forem.com/ahaoboy/improving-yt-dlp-ejs-with-rust-smaller-and-faster-5cnl</link>
      <guid>https://forem.com/ahaoboy/improving-yt-dlp-ejs-with-rust-smaller-and-faster-5cnl</guid>
      <description>&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://github.com/mpv-easy/mpv-easy" rel="noopener noreferrer"&gt;mpv-easy&lt;/a&gt; project, there's a &lt;a href="https://mpv-easy.github.io/mpv-build" rel="noopener noreferrer"&gt;web tool&lt;/a&gt; for customizing mpv players and scripts, including yt-dlp. To leverage GitHub CDN (which requires files under 25MB), file size is a constraint. Node/Bun/Deno runtimes are nearly impossible to compress below 25MB, and QuickJS performance in &lt;a href="https://github.com/yt-dlp/ejs" rel="noopener noreferrer"&gt;yt-dlp-ejs&lt;/a&gt; is suboptimal.&lt;/p&gt;

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

&lt;p&gt;The &lt;a href="https://github.com/yt-dlp/ejs" rel="noopener noreferrer"&gt;yt-dlp/ejs&lt;/a&gt; implementation uses meriyah to parse JavaScript, modifies the AST, regenerates code, and executes it via a JS engine.&lt;/p&gt;

&lt;p&gt;Profiling reveals that for lightweight engines like QuickJS and Boa, the bottleneck is code generation. When generating code from a large AST, extensive string concatenation occurs—something these engines don't optimize well. (Note: &lt;a href="https://github.com/quickjs-ng/quickjs/issues/1172#issuecomment-3590109901" rel="noopener noreferrer"&gt;QuickJS&lt;/a&gt; recently added optimizations for this scenario.)&lt;/p&gt;

&lt;p&gt;In contrast, SWC's code generation is highly efficient. This explains why SWC + QuickJS outperforms Deno/Node/Bun—their CLI startup time is comparable to JS execution time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[TRACE] → readFile
[TRACE] ← readFile (2.14ms)
[TRACE] → main
  [TRACE] → preprocessPlayer
    [TRACE] → parse
    [TRACE] ← parse (3187.57ms)
    [TRACE] → filterExpressions
    [TRACE] ← filterExpressions (251.01ms)
    [TRACE] → generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Using Rust, SWC replaces meriyah for AST manipulation. For Deno/Node/Bun, code is saved to a temp file and executed via CLI. For QuickJS/Boa, code is executed directly, eliminating CLI startup overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark Results (Ubuntu)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JavaScript Implementation
&lt;/h3&gt;

&lt;p&gt;Latest results: &lt;a href="https://github.com/ahaoboy/ejs/actions/workflows/bench.yml" rel="noopener noreferrer"&gt;bench.yml&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;Runtime&lt;/th&gt;
&lt;th&gt;Pass&lt;/th&gt;
&lt;th&gt;Fail&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;bun&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;93.207s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;node&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;90.037s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deno&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;100.980s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Rust Implementation
&lt;/h3&gt;

&lt;p&gt;Latest results: &lt;a href="https://github.com/ahaoboy/ytdlp-ejs/actions/workflows/bench.yml" rel="noopener noreferrer"&gt;bench.yml&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;Runtime&lt;/th&gt;
&lt;th&gt;Pass&lt;/th&gt;
&lt;th&gt;Fail&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;qjs&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;80.101s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;node&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;87.947s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bun&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;147.197s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;boa&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;178.557s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;deno&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;316&lt;/td&gt;
&lt;td&gt;238.250s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Binary Size Analysis
&lt;/h2&gt;

&lt;p&gt;Using &lt;a href="https://github.com/ahaoboy/bloaty-metafile" rel="noopener noreferrer"&gt;bloaty-metafile&lt;/a&gt; for analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Boa: ~6MB&lt;/li&gt;
&lt;li&gt;SWC: ~2MB&lt;/li&gt;
&lt;li&gt;QuickJS + std::core: ~1MB&lt;/li&gt;
&lt;/ul&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%2Flj9ts092txrrndaza8ab.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%2Flj9ts092txrrndaza8ab.png" alt="Size breakdown" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Boa's &lt;code&gt;intl_bundled&lt;/code&gt; feature, an additional ~10MB is added. Using SWC + QuickJS keeps the binary under 5MB.&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%2Fsnt69hfk9xzga5u4diwo.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%2Fsnt69hfk9xzga5u4diwo.png" alt="Size with intl" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Based on benchmarks, SWC + QuickJS appears to be a compelling alternative—faster execution with a smaller footprint. &lt;/p&gt;

</description>
      <category>rust</category>
      <category>ytdlp</category>
      <category>swc</category>
      <category>quickjs</category>
    </item>
    <item>
      <title>Analyzing OpenWrt Storage Usage with wiztree-metafile</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Sun, 30 Nov 2025 09:23:33 +0000</pubDate>
      <link>https://forem.com/ahaoboy/analyzing-openwrt-storage-usage-with-wiztree-metafile-539b</link>
      <guid>https://forem.com/ahaoboy/analyzing-openwrt-storage-usage-with-wiztree-metafile-539b</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/ahaoboy/wiztree-metafile" rel="noopener noreferrer"&gt;https://github.com/ahaoboy/wiztree-metafile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://esbuild.github.io/analyze/" rel="noopener noreferrer"&gt;https://esbuild.github.io/analyze/&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;ei ahaoboy/wiztree-metafile

wiztree-metafile / &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"/proc"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; w.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2r5xv5dfmkycgp7ij76.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%2Fs2r5xv5dfmkycgp7ij76.png" alt="openwrt-storage" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>openwrt</category>
      <category>wiztree</category>
      <category>metafile</category>
      <category>esbuild</category>
    </item>
    <item>
      <title>Building and Installing Neovim on OpenWrt</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Sun, 30 Nov 2025 04:22:04 +0000</pubDate>
      <link>https://forem.com/ahaoboy/building-and-installing-neovim-on-openwrt-40n1</link>
      <guid>https://forem.com/ahaoboy/building-and-installing-neovim-on-openwrt-40n1</guid>
      <description>&lt;p&gt;Pre-compiled Neovim binaries fail on OpenWrt with interpreter/linker errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei https://github.com/neovim/neovim/releases/download/nightly/nvim-linux-x86_64.tar.gz
nvim
&lt;span class="c"&gt;# Error: Failed to execute process: The file exists and is executable.&lt;/span&gt;
&lt;span class="c"&gt;# Check the interpreter or linker?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This happens due to glibc/musl incompatibility. Building from source ensures compatibility with OpenWrt's musl libc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This guide uses OpenWrt 24.10.4 x86_64. For other versions, refer to the &lt;a href="https://en.deeprouter.org/article/build-neovim-on-openwrt" rel="noopener noreferrer"&gt;original guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Dependencies
&lt;/h2&gt;

&lt;p&gt;Install the required build tools and libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;opkg update
opkg &lt;span class="nb"&gt;install &lt;/span&gt;git git-http python3 python3-pip make luajit gcc coreutils-install
pip &lt;span class="nb"&gt;install &lt;/span&gt;cmake
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fixing Missing Libraries
&lt;/h2&gt;

&lt;p&gt;OpenWrt's minimal environment lacks some standard libraries that Neovim expects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix Missing libdl
&lt;/h3&gt;

&lt;p&gt;The dynamic linker library is built into musl but needs a stub for linking:&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="s2"&gt;"!&amp;lt;arch&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /usr/lib/libdl.a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates an empty archive that satisfies the linker without adding actual code (musl already provides &lt;code&gt;dlopen&lt;/code&gt; and friends).&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix Missing libutil
&lt;/h3&gt;

&lt;p&gt;Create a dummy shared library for the utility functions:&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;"int main() { return 0; }"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; dummy.c
gcc &lt;span class="nt"&gt;-shared&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /usr/lib/libutil.so dummy.c
&lt;span class="nb"&gt;rm &lt;/span&gt;dummy.c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most &lt;code&gt;libutil&lt;/code&gt; functions (like &lt;code&gt;forkpty&lt;/code&gt;) are either unused by Neovim or provided by other libraries on musl systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Neovim
&lt;/h2&gt;

&lt;p&gt;Clone the repository (shallow clone to save space):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/neovim/neovim &lt;span class="nt"&gt;--depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="nb"&gt;cd &lt;/span&gt;neovim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build with release optimizations and debug symbols:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make &lt;span class="nv"&gt;CMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;RelWithDebInfo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes 10-30 minutes depending on your system. The &lt;code&gt;RelWithDebInfo&lt;/code&gt; build type provides good performance while keeping some debug information for troubleshooting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Neovim
&lt;/h2&gt;

&lt;p&gt;Install to the default location:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This installs to &lt;code&gt;/usr/local/bin/nvim&lt;/code&gt;. Create a symlink for convenience:&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;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; /usr/local/bin/nvim /usr/bin/nvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up LazyVim
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/LazyVim/starter" rel="noopener noreferrer"&gt;LazyVim&lt;/a&gt; is a modern Neovim configuration with sensible defaults and a plugin manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/LazyVim/starter &lt;span class="nt"&gt;--depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 ~/.config/nvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On first launch, Neovim will automatically install plugins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing tmux
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;opkg &lt;span class="nb"&gt;install &lt;/span&gt;tmux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>openwrt</category>
      <category>neovim</category>
      <category>nvim</category>
      <category>lazyvim</category>
    </item>
    <item>
      <title>Setting Up VS Code SSH Remote Development on OpenWrt</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Sat, 29 Nov 2025 14:45:21 +0000</pubDate>
      <link>https://forem.com/ahaoboy/setting-up-vs-code-ssh-remote-development-on-openwrt-42mb</link>
      <guid>https://forem.com/ahaoboy/setting-up-vs-code-ssh-remote-development-on-openwrt-42mb</guid>
      <description>&lt;p&gt;VS Code's Remote SSH extension requires SFTP (SSH File Transfer Protocol) support, which isn't available in Dropbear, OpenWrt's default SSH server. You'll need to switch to OpenSSH for full compatibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing OpenSSH
&lt;/h2&gt;

&lt;p&gt;Follow the &lt;a href="https://openwrt.org/docs/guide-user/services/ssh/openssh_instead_dropbear" rel="noopener noreferrer"&gt;official OpenWrt guide&lt;/a&gt; to replace Dropbear with OpenSSH&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Modern tar
&lt;/h2&gt;

&lt;p&gt;VS Code Remote requires a recent version of tar with specific features. OpenWrt's BusyBox tar is too limited:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;opkg &lt;span class="nb"&gt;install tar
tar&lt;/span&gt; &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring SSH on Your Host
&lt;/h2&gt;

&lt;p&gt;Create or edit your SSH config file to simplify connections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;: &lt;code&gt;C:\Users\YourUsername\.ssh\config&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Linux/Mac&lt;/strong&gt;: &lt;code&gt;~/.ssh/config&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add this configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host openwrt
  HostName 192.168.56.66
  User root
  IdentityFile ~/.ssh/openwrt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows you to connect with just &lt;code&gt;ssh openwrt&lt;/code&gt; instead of typing the full command each time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting with VS Code
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install the &lt;strong&gt;Remote - SSH&lt;/strong&gt; extension in VS Code&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;F1&lt;/code&gt; or &lt;code&gt;Ctrl+Shift+P&lt;/code&gt; to open the command palette&lt;/li&gt;
&lt;li&gt;Type "Remote-SSH: Connect to Host"&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;openwrt&lt;/code&gt; from the list&lt;/li&gt;
&lt;li&gt;VS Code will connect and install the VS Code Server on OpenWrt&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first connection takes a few minutes as VS Code downloads and installs its server components (~50-100MB).&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%2F3jtw2qtcw5sydj6uj6wr.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%2F3jtw2qtcw5sydj6uj6wr.png" alt="vscode ssh remote" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>openwrt</category>
      <category>openssh</category>
      <category>ssh</category>
    </item>
    <item>
      <title>Complete Guide to OpenWrt in VirtualBox: Setup and Disk Expansion</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Sat, 29 Nov 2025 14:19:59 +0000</pubDate>
      <link>https://forem.com/ahaoboy/complete-guide-to-openwrt-in-virtualbox-setup-and-disk-expansion-1fe2</link>
      <guid>https://forem.com/ahaoboy/complete-guide-to-openwrt-in-virtualbox-setup-and-disk-expansion-1fe2</guid>
      <description>&lt;p&gt;Default OpenWrt images have limited storage space. For development and testing, use pre-expanded images from &lt;a href="https://github.com/ahaoboy/openwrt-virtualbox-build/releases/tag/nightly" rel="noopener noreferrer"&gt;openwrt-virtualbox-build&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended&lt;/strong&gt;: &lt;code&gt;openwrt-24.10.4-x86-64-generic-ext4-combined.img.vdi&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The ext4 filesystem allows post-installation expansion if you need more space later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-Configuration: Network Setup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Critical&lt;/strong&gt;: Configure networking &lt;em&gt;before&lt;/em&gt; the first boot, or OpenWrt won't have internet access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure VirtualBox Host-Only Network
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open VirtualBox → &lt;strong&gt;File&lt;/strong&gt; → &lt;strong&gt;Host Network Manager&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Note the adapter IP (default: &lt;code&gt;192.168.56.1&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;DHCP Server&lt;/strong&gt; tab, &lt;strong&gt;uncheck "Enable Server"&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This prevents IP conflicts between VirtualBox's DHCP and OpenWrt's network configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Virtual Machine
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basic Settings
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OS Type&lt;/strong&gt;: Linux 2.6&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OS Version&lt;/strong&gt;: Linux 2.6 (64-bit)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt;: 4096 MB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CPU Cores&lt;/strong&gt;: 4&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Attach the Disk
&lt;/h3&gt;

&lt;p&gt;When prompted for a hard disk, select &lt;strong&gt;"Use an existing virtual hard disk file"&lt;/strong&gt; and choose the downloaded &lt;code&gt;.vdi&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network Configuration
&lt;/h3&gt;

&lt;p&gt;Configure two network adapters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adapter 1&lt;/strong&gt;: Host-Only Adapter (for management access from host)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapter 2&lt;/strong&gt;: Bridged Adapter (for internet access)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  First Boot Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Set Root Password
&lt;/h3&gt;

&lt;p&gt;After booting, immediately set the administrator password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;passwd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure Static IP
&lt;/h3&gt;

&lt;p&gt;Set OpenWrt's IP to match your host-only network range (&lt;code&gt;192.168.56.2-255&lt;/code&gt;). Choose a higher number to avoid conflicts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uci &lt;span class="nb"&gt;set &lt;/span&gt;network.lan.ipaddr&lt;span class="o"&gt;=&lt;/span&gt;192.168.56.66
uci commit
reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system will reboot with the new IP address.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up SSH Key Authentication
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Generate SSH Key on Host
&lt;/h3&gt;

&lt;p&gt;If you don't already have an SSH key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save it with a descriptive name like &lt;code&gt;~/.ssh/openwrt&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Public Key to OpenWrt
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Web UI&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;code&gt;http://192.168.56.66&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;System&lt;/strong&gt; → &lt;strong&gt;Administration&lt;/strong&gt; → &lt;strong&gt;SSH-Keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Paste the contents of your &lt;code&gt;~/.ssh/openwrt.pub&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add Key&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Option 2: Command Line&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OpenWrt uses Dropbear SSH server, which stores keys in a different location:&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;cat&lt;/span&gt; ~/.ssh/openwrt.pub | ssh root@192.168.56.66 &lt;span class="s2"&gt;"cat &amp;gt; /etc/dropbear/authorized_keys"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: The standard &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; path won't work with Dropbear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect via SSH
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh root@192.168.56.66 &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/openwrt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can simplify this by adding an entry to &lt;code&gt;~/.ssh/config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host openwrt
    HostName 192.168.56.66
    User root
    IdentityFile ~/.ssh/openwrt
    Port 22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then connect with just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh openwrt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Verifying Storage
&lt;/h2&gt;

&lt;p&gt;Check the current filesystem usage:&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;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initial output shows limited space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Filesystem                Size      Used Available Use% Mounted on
/dev/root                98.3M     25.5M     70.7M  27% /
tmpfs                     1.9G    204.0K      1.9G   0% /tmp
/dev/sda1                15.7M      5.7M      9.7M  37% /boot
tmpfs                   512.0K         0    512.0K   0% /dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only ~70MB is available on the root filesystem, even though the VDI image is 4GB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expanding the Root Filesystem
&lt;/h2&gt;

&lt;p&gt;To utilize the full 4GB capacity, follow the &lt;a href="https://openwrt.org/docs/guide-user/advanced/expand_root" rel="noopener noreferrer"&gt;official expansion guide&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;&lt;span class="c"&gt;# Install packages&lt;/span&gt;
opkg update
opkg &lt;span class="nb"&gt;install &lt;/span&gt;parted losetup resize2fs blkid

&lt;span class="c"&gt;# Download expand-root.sh&lt;/span&gt;
wget &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; expand-root.sh &lt;span class="s2"&gt;"https://openwrt.org/_export/code/docs/guide-user/advanced/expand_root?codeblock=0"&lt;/span&gt;

&lt;span class="c"&gt;# Source the script (creates /etc/uci-defaults/70-rootpt-resize and /etc/uci-defaults/80-rootpt-resize, and adds them to /etc/sysupgrade.conf so they will be re-run after a sysupgrade)&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; ./expand-root.sh

&lt;span class="c"&gt;# Resize root partition and filesystem (will resize partiton, reboot resize filesystem, and reboot again)&lt;/span&gt;
sh /etc/uci-defaults/70-rootpt-resize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify Expansion
&lt;/h3&gt;

&lt;p&gt;After the reboots complete, check storage again:&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;df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Filesystem                Size      Used Available Use% Mounted on
/dev/root                 4.0G     27.3M      4.0G   1% /
tmpfs                     1.9G    188.0K      1.9G   0% /tmp
/dev/sda1                15.7M      5.7M      9.7M  37% /boot
tmpfs                   512.0K         0    512.0K   0% /dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The root filesystem now has ~4GB available, perfect for development work.&lt;/p&gt;

</description>
      <category>virtualbox</category>
      <category>openwrt</category>
      <category>ssh</category>
      <category>linux</category>
    </item>
    <item>
      <title>Running QuickJS Engine with Rust on OpenWrt</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Sat, 29 Nov 2025 13:26:04 +0000</pubDate>
      <link>https://forem.com/ahaoboy/running-quickjs-engine-with-rust-on-openwrt-4fpd</link>
      <guid>https://forem.com/ahaoboy/running-quickjs-engine-with-rust-on-openwrt-4fpd</guid>
      <description>&lt;h2&gt;
  
  
  Installing Dependencies
&lt;/h2&gt;

&lt;p&gt;Install the required build tools and development packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;opkg &lt;span class="nb"&gt;install &lt;/span&gt;git git-http python3 python3-pip make gcc coreutils-install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing CMake
&lt;/h2&gt;

&lt;p&gt;CMake is required for building native dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;cmake
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing Rust
&lt;/h2&gt;

&lt;p&gt;Install Rust using rustup, the official Rust toolchain installer:&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;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building and Running QuickJS
&lt;/h2&gt;

&lt;p&gt;Clone the rquickjs-cli test repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ahaoboy/rquickjs-cli.git
&lt;span class="nb"&gt;cd &lt;/span&gt;rquickjs-cli/
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"console.log('hello openwrt')"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; test.js
cargo run &lt;span class="nt"&gt;--&lt;/span&gt; ./test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Expected Output
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hello openwrt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>rust</category>
      <category>quickjs</category>
      <category>openwrt</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Running Node.js and Modern Web Development Tools on OpenWrt</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Fri, 28 Nov 2025 15:40:21 +0000</pubDate>
      <link>https://forem.com/ahaoboy/running-nodejs-and-modern-web-development-tools-on-openwrt-2jh</link>
      <guid>https://forem.com/ahaoboy/running-nodejs-and-modern-web-development-tools-on-openwrt-2jh</guid>
      <description>&lt;h2&gt;
  
  
  Prerequisites and Limitations
&lt;/h2&gt;

&lt;p&gt;This guide is specifically for &lt;strong&gt;x86 architecture only&lt;/strong&gt;. On ARM devices, both pnpm and Node.js may fail due to &lt;code&gt;libgcc_s.so.1&lt;/code&gt; dependency issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  System Configuration
&lt;/h2&gt;

&lt;p&gt;First, configure your build target for musl-based systems:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei config x86_64-unknown-linux-musl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing Required Dependencies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install libstdc++
&lt;/h3&gt;

&lt;p&gt;OpenWrt's minimal environment lacks the C++ standard library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;opkg &lt;span class="nb"&gt;install &lt;/span&gt;libstdcpp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Bash
&lt;/h3&gt;

&lt;p&gt;OpenWrt ships with a basic &lt;code&gt;sh&lt;/code&gt; shell, but Node.js and pnpm require bash's advanced syntax features.&lt;/p&gt;

&lt;p&gt;Download a static bash binary from &lt;a href="https://github.com/robxu9/bash-static/releases" rel="noopener noreferrer"&gt;robxu9/bash-static&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;ei robxu9/bash-static
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the default shell symlinks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which bash
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; /root/.ei/bash /bin/sh
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; /root/.ei/bash /bin/bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing Node.js
&lt;/h2&gt;

&lt;p&gt;Node.js requires approximately 200MB of storage. On space-constrained OpenWrt devices, install to &lt;code&gt;/tmp&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;ei https://unofficial-builds.nodejs.org/download/release/v25.2.1/node-v25.2.1-linux-x64-musl.tar.xz &lt;span class="nt"&gt;-d&lt;/span&gt; /tmp
node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Use the &lt;a href="https://unofficial-builds.nodejs.org/download/release/" rel="noopener noreferrer"&gt;unofficial-builds&lt;/a&gt; repository for musl-compatible binaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Package Managers and Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install pnpm
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei pnpm/pnpm
pnpm &lt;span class="nt"&gt;--version&lt;/span&gt;

&lt;span class="c"&gt;# pnpm fish completions&lt;/span&gt;
ei ahaoboy/coreutils-build &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nb"&gt;stat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Git (Gitoxide)
&lt;/h3&gt;

&lt;p&gt;For a lightweight Git implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei GitoxideLabs/gitoxide
gix &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating and Running a Vite Project
&lt;/h2&gt;

&lt;p&gt;Now you can use modern web development tools:&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 new Vite project&lt;/span&gt;
pnpm dlx create-vite

&lt;span class="c"&gt;# Navigate to your project&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;react-ts

&lt;span class="c"&gt;# Start the development server (accessible from network)&lt;/span&gt;
pnpm run dev &lt;span class="nt"&gt;--host&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--host&lt;/code&gt; flag exposes the dev server to your local network, allowing you to access it from other devices.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>openwrt</category>
      <category>node</category>
      <category>react</category>
    </item>
    <item>
      <title>openwrt: error while loading shared libraries: libgcc_s.so.1: wrong ELF class: ELFCLASS32</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Thu, 20 Nov 2025 06:41:20 +0000</pubDate>
      <link>https://forem.com/ahaoboy/openwrt-error-while-loading-shared-libraries-libgccsso1-wrong-elf-class-elfclass32-4pnl</link>
      <guid>https://forem.com/ahaoboy/openwrt-error-while-loading-shared-libraries-libgccsso1-wrong-elf-class-elfclass32-4pnl</guid>
      <description>&lt;p&gt;The 32-bit version of libgcc_s.so.1 was used on the 64-bit system.&lt;/p&gt;

&lt;h2&gt;
  
  
  RT-BE88U-A1F0
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
Linux RT-BE88U-A1F0 4.19.294 &lt;span class="c"&gt;#1 SMP PREEMPT Wed Jan 22 22:58:22 CST 2025 aarch64 RT-BE88U_Koolcenter_mod&lt;/span&gt;

file /lib/libgcc_s.so.1
libgcc_s.so.1: ELF 32-bit LSB shared object, ARM, EABI5 version 1 &lt;span class="o"&gt;(&lt;/span&gt;SYSV&lt;span class="o"&gt;)&lt;/span&gt;, dynamically linked, stripped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  openwrt
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
Linux OpenWrt 6.6.110 &lt;span class="c"&gt;#0 SMP Sun Oct 19 16:37:45 2025 x86_64 GNU/Linux&lt;/span&gt;

file /lib/libgcc_s.so.1
./libgcc_s.so.1: ELF 64-bit LSB shared object, x86-64, version 1 &lt;span class="o"&gt;(&lt;/span&gt;SYSV&lt;span class="o"&gt;)&lt;/span&gt;, dynamically linked, no section header
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>openwrt</category>
      <category>libgcc</category>
    </item>
    <item>
      <title>easy-install: A Rust-Powered Package Installer That Actually Works on OpenWrt</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Fri, 14 Nov 2025 10:06:06 +0000</pubDate>
      <link>https://forem.com/ahaoboy/easy-install-a-rust-powered-package-installer-that-actually-works-on-openwrt-58pa</link>
      <guid>https://forem.com/ahaoboy/easy-install-a-rust-powered-package-installer-that-actually-works-on-openwrt-58pa</guid>
      <description>&lt;h2&gt;
  
  
  What is easy-install?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/easy-install/easy-install" rel="noopener noreferrer"&gt;easy-install&lt;/a&gt; is a cross-platform cli tool written in rust that simplifies installing binaries from GitHub releases and other sources. Think of it as a universal package installer that works across windows, linux, macOS, android and OpenWrt routers.&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%2Futksabxf0q6e6d396z7n.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%2Futksabxf0q6e6d396z7n.png" alt="neofetch-openwrt" width="800" height="662"&gt;&lt;/a&gt;&lt;br&gt;
The beauty of ei is that it handles all the tedious stuff automatically: downloading the correct binary for your platform, extracting archives (even formats like xz that some devices don't support), setting permissions, and managing your PATH.&lt;/p&gt;

&lt;p&gt;OpenWrt devices typically have extremely limited storage—often just 30-100MB of usable space. Plus, many regions have restricted GitHub access, and some systems blacklist curl/wget for GitHub domains. easy-install handles all these edge cases elegantly with built-in proxy support and automatic compression.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Getting started is simple. Use curl or wget:&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/easy-install/easy-install/main/install.sh | sh

wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; https://raw.githubusercontent.com/easy-install/easy-install/main/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if GitHub access is restricted in your region, use a CDN proxy:&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://cdn.jsdelivr.net/gh/ahaoboy/ei-assets/install.sh | sh &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--proxy&lt;/span&gt; jsdelivr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This installs ei to &lt;code&gt;~/.ei/ei&lt;/code&gt;. Add it to your PATH:&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;export &lt;/span&gt;&lt;span class="nv"&gt;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;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ei:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration for OpenWrt
&lt;/h2&gt;

&lt;p&gt;Configure ei for your architecture (I recommend musl to avoid libgcc_s.so.1 errors):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei config target x86_64-unknown-linux-musl  &lt;span class="c"&gt;# or aarch64-unknown-linux-musl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If GitHub is blocked, set up a proxy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei config proxy gh-proxy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For storage-constrained devices, you can change the install directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei config &lt;span class="nb"&gt;dir&lt;/span&gt; /tmp/large_ei
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The UPX Trick
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. Most OpenWrt devices have very limited storage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Filesystem                Size      Used Available Use% Mounted on
/dev/root                98.3M     25.5M     70.7M  27% /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/upx/upx" rel="noopener noreferrer"&gt;UPX&lt;/a&gt;&lt;/strong&gt; (Ultimate Packer for eXecutables) is a compression tool that can reduce binary sizes by 30-60%. install it with ei:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei upx/upx
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;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;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.ei/upx:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compress ei itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;upx ~/.ei/ei

     File size         Ratio      Format      Name
&lt;span class="nt"&gt;--------------------&lt;/span&gt;   &lt;span class="nt"&gt;------&lt;/span&gt;   &lt;span class="nt"&gt;-----------&lt;/span&gt;   &lt;span class="nt"&gt;-----------&lt;/span&gt;
5726880 -&amp;gt;   2388972   41.72%   linux/amd64   ei
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable automatic UPX compression for all future installs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei config upx &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Software I've Installed
&lt;/h2&gt;

&lt;p&gt;Here are some tools I'm running on my OpenWrt router, all installed with a single command:&lt;/p&gt;

&lt;h3&gt;
  
  
  Fish Shell
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/fish-shell/fish-shell" rel="noopener noreferrer"&gt;Fish&lt;/a&gt; is a user-friendly, cross-platform shell with excellent autocompletion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei fish-shell/fish-shell
&lt;span class="c"&gt;# Output: -rwxr-xr-x 14.5M fish -&amp;gt; 2.9M /root/.ei/fish&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a 14.5MB binary compressed down to 2.9MB!&lt;/p&gt;

&lt;h3&gt;
  
  
  Starship
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/starship/starship" rel="noopener noreferrer"&gt;Starship&lt;/a&gt; is a blazing-fast, customizable prompt written in rust. It works across any shell and looks gorgeous.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei starship/starship
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Coreutils (rust Edition)
&lt;/h3&gt;

&lt;p&gt;If you hit missing dependency errors (like &lt;code&gt;mktemp&lt;/code&gt;), &lt;a href="https://github.com/uutils/coreutils" rel="noopener noreferrer"&gt;uutils/coreutils&lt;/a&gt; provides rust implementations of Unix core utilities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei ahaoboy/coreutils-build &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nb"&gt;mktemp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Neofetch Alternative
&lt;/h3&gt;

&lt;p&gt;The original &lt;a href="https://github.com/dylanaraps/neofetch" rel="noopener noreferrer"&gt;neofetch&lt;/a&gt; doesn't work well with OpenWrt's default sh. There's a rust implementation that works perfectly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei ahaoboy/neofetch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could also use &lt;a href="https://github.com/reubeno/brush" rel="noopener noreferrer"&gt;Brush&lt;/a&gt;, a rust-based bash shell implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dufs
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/sigoden/dufs" rel="noopener noreferrer"&gt;Dufs&lt;/a&gt; is a powerful file server with WebDAV support—perfect for sharing media across your local network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei sigoden/dufs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Amp
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/jmacdonald/amp" rel="noopener noreferrer"&gt;Amp&lt;/a&gt; is a text editor with syntax highlighting support for multiple languages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei jmacdonald/amp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  iperf3
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/userdocs/iperf3-static" rel="noopener noreferrer"&gt;iperf3-static&lt;/a&gt; is essential for network speed testing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ei userdocs/iperf3-static
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>openwrt</category>
      <category>rust</category>
      <category>github</category>
      <category>tool</category>
    </item>
    <item>
      <title>I shrunk my Rust binary from 11MB to 4.5MB with bloaty-metafile</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Sun, 09 Nov 2025 06:48:51 +0000</pubDate>
      <link>https://forem.com/ahaoboy/i-shrunk-my-rust-binary-from-11mb-to-45mb-with-bloaty-metafile-1n7i</link>
      <guid>https://forem.com/ahaoboy/i-shrunk-my-rust-binary-from-11mb-to-45mb-with-bloaty-metafile-1n7i</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Used bloaty-metafile to analyze binary size, disabled default features on key dependencies, reduced size by 59% (11MB → 4.5MB)&lt;/p&gt;

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

&lt;p&gt;I've been working on &lt;a href="https://github.com/easy-install/easy-install" rel="noopener noreferrer"&gt;easy-install&lt;/a&gt; (&lt;code&gt;ei&lt;/code&gt;), a CLI tool that automatically downloads and installs binaries from GitHub releases based on your OS and architecture. Think of it like a universal package manager for GitHub releases.&lt;/p&gt;

&lt;p&gt;Example: &lt;code&gt;ei ilai-deutel/kibi&lt;/code&gt; automatically downloads the right binary for your platform, extracts it to &lt;code&gt;~/.ei&lt;/code&gt;, and adds it to your shell's PATH.&lt;/p&gt;

&lt;p&gt;I wanted to run this on OpenWrt routers, which typically have only ~30MB of available storage. Even with standard release optimizations, the binary was still ~10MB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[profile.release]&lt;/span&gt;
&lt;span class="py"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="py"&gt;lto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;strip&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;opt-level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="py"&gt;codegen-units&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="py"&gt;panic&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abort"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not good enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Analysis
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://github.com/ahaoboy/bloaty-metafile" rel="noopener noreferrer"&gt;bloaty-metafile&lt;/a&gt; to analyze where the bloat was coming from. Turns out, ~80% of the binary size came from just 20% of dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;clap&lt;/strong&gt; - CLI argument parsing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;reqwest&lt;/strong&gt; - HTTP downloads&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tokio&lt;/strong&gt; - Async runtime&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;regex&lt;/strong&gt; - Parsing non-standard release filenames (e.g., &lt;code&gt;biome-linux-x64-musl&lt;/code&gt; → &lt;code&gt;x86_64-unknown-linux-musl&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;easy-archive&lt;/strong&gt; - Archive extraction (tar.gz, zip, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Optimization
&lt;/h2&gt;

&lt;p&gt;The key insight: &lt;strong&gt;disable default features and only enable what you actually use&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. clap - Saved 100-200KB
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;clap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"derive"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"std"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="py"&gt;default-features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only enable basic functionality. No color output, no suggestions, no fancy formatting.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. reqwest - Saved ~4MB (!!)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;reqwest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.12"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"rustls-tls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c"&gt;# Instead of native-tls&lt;/span&gt;
  &lt;span class="s"&gt;"gzip"&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="py"&gt;default-features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Switching from &lt;code&gt;native-tls&lt;/code&gt; to &lt;code&gt;rustls-tls&lt;/code&gt; was the biggest win. Native TLS pulls in system dependencies that bloat the binary significantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. tokio - Saved ~100KB
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;tokio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s"&gt;"macros"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"rt-multi-thread"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="py"&gt;default-features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only enable the multi-threaded runtime and macros. No I/O, no time, no sync primitives we don't use.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. regex - Saved ~1MB
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;default-features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"std"&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;Since we only use regex occasionally for URL parsing, we can disable Unicode support and other features.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. easy-archive - Saved ~1MB
&lt;/h3&gt;

&lt;p&gt;Only enable tar.gz decoding, skip encoding and other formats we don't need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt; 11MB&lt;br&gt;
&lt;strong&gt;After:&lt;/strong&gt; 4.5MB&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%2Fsgo7bxd6ahu9arpidoif.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%2Fsgo7bxd6ahu9arpidoif.png" alt=" " width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most crates enable way more than you need. The 80/20 rule applies here - optimizing a few key dependencies can yield massive savings.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/easy-install/easy-install" rel="noopener noreferrer"&gt;easy-install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ahaoboy/bloaty-metafile" rel="noopener noreferrer"&gt;bloaty-metafile&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>bloaty</category>
      <category>programming</category>
      <category>metafile</category>
    </item>
    <item>
      <title>Run FishShell anywhere~</title>
      <dc:creator>阿豪</dc:creator>
      <pubDate>Fri, 17 Oct 2025 13:04:07 +0000</pubDate>
      <link>https://forem.com/ahaoboy/run-fishshell-anywhere-2eje</link>
      <guid>https://forem.com/ahaoboy/run-fishshell-anywhere-2eje</guid>
      <description>&lt;p&gt;Finally got fish running on all my devices&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%2F6kl43qgm3qtd6w7zyqij.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%2F6kl43qgm3qtd6w7zyqij.png" alt=" " width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>fishshell</category>
      <category>neofetch</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
