<?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: Michael</title>
    <description>The latest articles on DEV Community by Michael (@michael_ed0600820f49eb89a).</description>
    <link>https://dev.to/michael_ed0600820f49eb89a</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%2F4214207%2F94734831-a7ce-4daf-b9f8-86a0d116a879.png</url>
      <title>DEV Community: Michael</title>
      <link>https://dev.to/michael_ed0600820f49eb89a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/michael_ed0600820f49eb89a"/>
    <language>en</language>
    <item>
      <title>How I Cut 40KB from My Edge Bundle with Zero-Dep Utils</title>
      <dc:creator>Michael</dc:creator>
      <pubDate>Thu, 29 Oct 2026 03:57:34 +0000</pubDate>
      <link>https://dev.to/michael_ed0600820f49eb89a/how-i-cut-40kb-from-my-edge-bundle-with-zero-dep-utils-3k16</link>
      <guid>https://dev.to/michael_ed0600820f49eb89a/how-i-cut-40kb-from-my-edge-bundle-with-zero-dep-utils-3k16</guid>
      <description>&lt;p&gt;When I started building edge services on Cloudflare Workers, I kept hitting the same problem: &lt;strong&gt;bundle size&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Every "lightweight" utility pulled in dependencies. &lt;code&gt;zod&lt;/code&gt; (1.1 MB), &lt;code&gt;p-retry&lt;/code&gt; (7 KB + deps), &lt;code&gt;axios-retry&lt;/code&gt; (requires axios). On Workers where cold starts matter, every KB counts.&lt;/p&gt;

&lt;p&gt;So I built three zero-dependency replacements:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. fetch-retry-jitter (1.6 KB gzip)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Replaces:&lt;/strong&gt; &lt;code&gt;p-retry&lt;/code&gt;, &lt;code&gt;axios-retry&lt;/code&gt;, custom retry loops&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;fetchRetry&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;fetch-retry-jitter&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com/data&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="na"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;baseDelayMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;maxDelayMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;circuitBreaker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;failureThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;resetTimeoutMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;timeoutMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;deduplicate&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Exponential backoff with &lt;strong&gt;full jitter&lt;/strong&gt; (AWS recommended)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit breaker&lt;/strong&gt; (closed/open/half-open states)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request deduplication&lt;/strong&gt; — coalesces identical in-flight requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry-After&lt;/strong&gt; header support (seconds + HTTP-date)&lt;/li&gt;
&lt;li&gt;Per-attempt &lt;code&gt;timeoutMs&lt;/code&gt; + &lt;code&gt;retryIf&lt;/code&gt; predicate&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AbortSignal&lt;/code&gt; support + stream body protection&lt;/li&gt;
&lt;li&gt;1.6 KB gzip, zero dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. env-assert-typed (528 B gzip)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Replaces:&lt;/strong&gt; Zod (1.1 MB), Valibot (188 KB), Joi (50 KB+)&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;envAssert&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;env-assert-typed&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;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;envAssert&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;required&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="na"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&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;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;REGION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;required&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="na"&gt;choices&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;us&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;eu&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="na"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;required&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="na"&gt;secret&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic TypeScript inference&lt;/strong&gt; — required → &lt;code&gt;T&lt;/code&gt;, default → &lt;code&gt;T&lt;/code&gt;, optional → &lt;code&gt;T | undefined&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discriminated union schema&lt;/strong&gt; — compile errors on mismatched &lt;code&gt;default&lt;/code&gt;/&lt;code&gt;choices&lt;/code&gt; types&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;coerce&lt;/code&gt; — custom string→type parsing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;refine&lt;/code&gt; — cross-field validation with access to all env&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;refineAsync&lt;/code&gt; — async refinement hook&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;transform&lt;/code&gt; — post-coercion transformation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;secret&lt;/code&gt; — marks sensitive values for error masking&lt;/li&gt;
&lt;li&gt;Factory functions for defaults&lt;/li&gt;
&lt;li&gt;528 B gzip, zero dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. ci-diff-changed (Action, ~80 lines bash)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Replaces&lt;/strong&gt; &lt;code&gt;tj-actions/changed-files&lt;/code&gt; (Node container + API calls)&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="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Yearnless/ci-diff-changed@v1&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;diff&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;base-ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;origin/main&lt;/span&gt;
    &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;packages/(api|web)/'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outputs JSON array of changed files — perfect for conditional CI in monorepos.&lt;/p&gt;




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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Savings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;zod (1.1 MB)&lt;/td&gt;
&lt;td&gt;env-assert-typed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;99.9% smaller&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p-retry (7 KB + deps)&lt;/td&gt;
&lt;td&gt;fetch-retry-jitter&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~75% smaller&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tj-actions/changed-files (container)&lt;/td&gt;
&lt;td&gt;ci-diff-changed (bash)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No container&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Total bundle reduction: &lt;strong&gt;~40 KB → ~2 KB&lt;/strong&gt; (95% reduction)&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Zero-Dep Matters on the Edge
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cold starts&lt;/strong&gt; — Every KB adds milliseconds to cold start&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bundle limits&lt;/strong&gt; — Workers free tier: 1 MB, paid: 10 MB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supply chain&lt;/strong&gt; — Zero deps = zero supply chain risk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auditability&lt;/strong&gt; — Read the entire source in 5 minutes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try Them
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i fetch-retry-jitter env-assert-typed
&lt;span class="c"&gt;# GitHub Action:&lt;/span&gt;
&lt;span class="c"&gt;# uses: Yearnless/ci-diff-changed@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All three include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Provenance-signed npm packages&lt;/li&gt;
&lt;li&gt;✅ Full TypeScript inference&lt;/li&gt;
&lt;li&gt;✅ 100% test coverage&lt;/li&gt;
&lt;li&gt;✅ Zero dependencies&lt;/li&gt;
&lt;li&gt;✅ Works on Node, Bun, Deno, Cloudflare Workers, browsers&lt;/li&gt;
&lt;/ul&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Yearnless/fetch-retry-jitter" rel="noopener noreferrer"&gt;fetch-retry-jitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yearnless/env-assert-typed" rel="noopener noreferrer"&gt;env-assert-typed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yearnless/ci-diff-changed" rel="noopener noreferrer"&gt;ci-diff-changed&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Starter templates using them:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Yearnless/cloudflare-worker-minimal-template" rel="noopener noreferrer"&gt;cloudflare-worker-minimal-template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yearnless/hono-microservice-starter" rel="noopener noreferrer"&gt;hono-microservice-starter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Yearnless/ts-monorepo-boilerplate" rel="noopener noreferrer"&gt;ts-monorepo-boilerplate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built while learning in public. Feedback welcome!&lt;/em&gt;&lt;/p&gt;




</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
