<?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: KhaledSalem</title>
    <description>The latest articles on Forem by KhaledSalem (@khaledmsalem).</description>
    <link>https://forem.com/khaledmsalem</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%2F3565357%2F72721ed3-cc00-44d0-89e6-86b75ca3f59c.png</url>
      <title>Forem: KhaledSalem</title>
      <link>https://forem.com/khaledmsalem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/khaledmsalem"/>
    <language>en</language>
    <item>
      <title>Plugins Are Powerful. But They Shouldn’t Become Your Architecture.</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Mon, 11 May 2026 16:27:53 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/plugins-are-powerful-but-they-shouldnt-become-your-architecture-3gb4</link>
      <guid>https://forem.com/khaledmsalem/plugins-are-powerful-but-they-shouldnt-become-your-architecture-3gb4</guid>
      <description>&lt;p&gt;Plugin systems are one of the reasons modern frontend tooling became so flexible.&lt;/p&gt;

&lt;p&gt;Vite proved this extremely well.&lt;/p&gt;

&lt;p&gt;A good plugin system lets a tool support frameworks, experiments, edge cases, and ecosystem creativity without forcing everything into the core.&lt;/p&gt;

&lt;p&gt;But there is a point where something changes.&lt;/p&gt;

&lt;p&gt;Plugins stop being extensions.&lt;/p&gt;

&lt;p&gt;They become architecture.&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%2Fe3a0rfwfa4dchzsp91bo.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%2Fe3a0rfwfa4dchzsp91bo.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And once foundational behavior lives across many plugin hooks, the cost is no longer just “install one more package”.&lt;/p&gt;

&lt;p&gt;The cost becomes engineering complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The plugin cost is not the package&lt;/strong&gt;&lt;br&gt;
When people talk about plugins, they usually talk about installation:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;But that is not the real cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real cost is:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;hook ordering&lt;/li&gt;
&lt;li&gt;duplicated graph knowledge&lt;/li&gt;
&lt;li&gt;dev/build parity&lt;/li&gt;
&lt;li&gt;cache invalidation&lt;/li&gt;
&lt;li&gt;transform boundaries&lt;/li&gt;
&lt;li&gt;hidden runtime assumptions&lt;/li&gt;
&lt;li&gt;debugging intermediate output&lt;/li&gt;
&lt;li&gt;plugin compatibility across versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A plugin can add a feature.&lt;/p&gt;

&lt;p&gt;But if the feature affects the module graph, dependency identity, runtime behavior, or cache correctness, then the build engine needs to understand it deeply.&lt;/p&gt;

&lt;p&gt;Not just call a hook and hope the result still makes sense.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Five features Ionify treats as native&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ionify is built around a simple idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Foundational build behavior should be understood by the engine, not reconstructed through plugin layers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are five examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. React should not need a plugin to start&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In many frontend setups, React support is treated as a plugin concern.&lt;/p&gt;

&lt;p&gt;That usually means JSX/TSX transforms, Fast Refresh wiring, runtime overlays, and production stripping need to be coordinated across the dev server and production build.&lt;/p&gt;

&lt;p&gt;The engineering cost is not “React support”.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cost is keeping these pieces consistent:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;JSX/TSX transform behavior&lt;/li&gt;
&lt;li&gt;Fast Refresh boundaries&lt;/li&gt;
&lt;li&gt;error overlay/runtime injection&lt;/li&gt;
&lt;li&gt;production-only stripping&lt;/li&gt;
&lt;li&gt;dev/build parity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ionify&lt;/strong&gt; handles this natively.&lt;/p&gt;

&lt;p&gt;React is not treated as an external behavior bolted onto the build.&lt;br&gt;
The engine understands the React path directly, which means fewer moving parts before the app even starts.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2. Resolution should be one authority&lt;/strong&gt;&lt;br&gt;
Aliases, workspace paths, tsconfig paths, package exports, browser fields, peer dependency identity — these are not small details.&lt;/p&gt;

&lt;p&gt;They define what a module is.&lt;/p&gt;

&lt;p&gt;When resolution is spread across plugin layers, different parts of the toolchain can develop slightly different answers to the same question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does this import point to?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  That creates painful bugs:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;works in dev, fails in build&lt;/li&gt;
&lt;li&gt;duplicate copies of a dependency&lt;/li&gt;
&lt;li&gt;broken peer singletons&lt;/li&gt;
&lt;li&gt;incorrect workspace resolution&lt;/li&gt;
&lt;li&gt;alias behavior that differs from TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ionify&lt;/strong&gt; uses a native resolver with support for aliases, tsconfig / jsconfig paths, package exports/imports/browser fields, and workspace-aware ids.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One import should have one identity.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;3. CommonJS compatibility should not be a guessing game&lt;/strong&gt;&lt;br&gt;
CommonJS is still everywhere.&lt;/p&gt;

&lt;p&gt;The difficult part is not simply “convert CJS to ESM”.&lt;/p&gt;

&lt;p&gt;The difficult part is recovering the shape of exports safely enough that browser ESM can consume it predictably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugin-based CJS conversion can become expensive because it sits at the boundary between:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;dependency optimization&lt;/li&gt;
&lt;li&gt;dev-time ESM serving&lt;/li&gt;
&lt;li&gt;production bundling&lt;/li&gt;
&lt;li&gt;named export recovery&lt;/li&gt;
&lt;li&gt;default export interop&lt;/li&gt;
&lt;li&gt;cache correctness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Ionify&lt;/strong&gt; handles CJS-to-browser-safe ESM natively in Rust, including export analysis and default/named export recovery.&lt;/p&gt;

&lt;p&gt;That means CommonJS compatibility becomes part of the engine’s dependency model instead of an after-the-fact transform.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;4. Dependency optimization should not be separate from the graph&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dependency optimization is one of the most important parts of modern frontend tooling.&lt;/p&gt;

&lt;p&gt;It affects startup time, browser request counts, cache reuse, shared chunks, and vendor behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  The hidden cost appears when dependency optimization is treated as a separate pre-step instead of part of the engine’s persistent understanding of the project.
&lt;/h3&gt;

&lt;h2&gt;
  
  
  You end up asking:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Was this dependency already optimized?&lt;/li&gt;
&lt;li&gt;Did the graph change?&lt;/li&gt;
&lt;li&gt;Is this wrapper deterministic?&lt;/li&gt;
&lt;li&gt;Can this output be reused?&lt;/li&gt;
&lt;li&gt;Should this vendor pack be shared?&lt;/li&gt;
&lt;li&gt;Why did this dependency rebuild?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ionify treats dependency optimization as native graph work.&lt;/p&gt;

&lt;p&gt;It has native /@deps optimization, deterministic dependency wrappers, shared chunks, vendor packs, and slimming.&lt;/p&gt;

&lt;p&gt;The important part is not just speed.&lt;/p&gt;

&lt;p&gt;The important part is that dependency optimization belongs to the same engine that understands the graph&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;5. CSS should have dev/build parity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CSS looks simple until it touches real applications.&lt;br&gt;
Then you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostCSS config&lt;/li&gt;
&lt;li&gt;CSS Modules tokens&lt;/li&gt;
&lt;li&gt;?inline&lt;/li&gt;
&lt;li&gt;?raw&lt;/li&gt;
&lt;li&gt;?url&lt;/li&gt;
&lt;li&gt;?module&lt;/li&gt;
&lt;li&gt;assets referenced from CSS&lt;/li&gt;
&lt;li&gt;HMR behavior&lt;/li&gt;
&lt;li&gt;production extraction&lt;/li&gt;
&lt;li&gt;class name generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The engineering cost is making all of that behave the same way in dev and build.&lt;/p&gt;

&lt;p&gt;When CSS is handled through disconnected transforms, it is easy for one mode to understand something another mode does not.&lt;/p&gt;

&lt;p&gt;Ionify handles core CSS, PostCSS, CSS Modules, and CSS query modes natively.&lt;/p&gt;

&lt;p&gt;The goal is not to make CSS magical.&lt;br&gt;
The goal is to make CSS boring.&lt;/p&gt;

&lt;p&gt;Boring is good.&lt;br&gt;
Boring means fewer surprises.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;And more...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Those are only five examples.&lt;br&gt;
Ionify also handles more build behavior natively, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;static assets&lt;/li&gt;
&lt;li&gt;images, fonts, SVGs, hashed build assets, and publicDir&lt;/li&gt;
&lt;li&gt;build precompression with .br and .gz&lt;/li&gt;
&lt;li&gt;compression manifests and compression CAS&lt;/li&gt;
&lt;li&gt;SPA history fallback with internal/asset exclusions&lt;/li&gt;
&lt;li&gt;.env, define, import.meta.env, and process.env.NODE_ENV&lt;/li&gt;
&lt;li&gt;basic analyzer output through ionify analyze, build.stats.json, graph/deps/manifest authorities&lt;/li&gt;
&lt;li&gt;manifest-driven ESM federation work, where the graph direction matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not every feature belongs in core.&lt;br&gt;
But foundational behavior does.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The real difference: hooks vs understanding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A plugin hook can transform a file.&lt;/p&gt;

&lt;h2&gt;
  
  
  But the engine still has to answer deeper questions:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What changed?&lt;/li&gt;
&lt;li&gt;What can be reused?&lt;/li&gt;
&lt;li&gt;What depends on this?&lt;/li&gt;
&lt;li&gt;Is this output still valid?&lt;/li&gt;
&lt;li&gt;Is this module the same identity as before?&lt;/li&gt;
&lt;li&gt;Does dev behavior match build behavior?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the engine does not understand the feature, the plugin has to simulate that understanding from the outside.&lt;/p&gt;

&lt;p&gt;That is where complexity grows.&lt;/p&gt;

&lt;p&gt;Ionify’s bet is that many common build features should not be simulated from the outside.&lt;/p&gt;

&lt;p&gt;They should be native engine concepts.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;This is not anti-plugin&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Plugins are still valuable.&lt;/p&gt;

&lt;p&gt;There will always be project-specific needs, framework experiments, integrations, and custom behavior that should live outside the core.&lt;/p&gt;

&lt;p&gt;But the foundation should be stable.&lt;/p&gt;

&lt;p&gt;React startup, module identity, dependency optimization, CommonJS compatibility, CSS behavior, assets, env handling, federation, and build compression are not exotic edge cases.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They are daily build-system work.&lt;br&gt;
Ionify tries to make that work native.&lt;br&gt;
Less hook choreography.&lt;br&gt;
Less duplicated graph logic.&lt;br&gt;
Less rebuilding what the engine should already know.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The question
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Where do you draw the line?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which build features should be native to the engine, and which ones should stay as plugins?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  I’m genuinely curious how other teams think about this.
&lt;/h3&gt;

</description>
      <category>frontend</category>
      <category>react</category>
      <category>javascript</category>
      <category>architecture</category>
    </item>
    <item>
      <title>The React Native Architecture Chain — Metro, Hermes, JSI, Yoga &amp; Fabric</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Sun, 10 May 2026 07:56:55 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/the-react-native-architecture-chain-metro-hermes-jsi-yoga-fabric-4n7c</link>
      <guid>https://forem.com/khaledmsalem/the-react-native-architecture-chain-metro-hermes-jsi-yoga-fabric-4n7c</guid>
      <description>&lt;p&gt;Most React Native devs use these five pieces every single day without knowing how they connect. Let's fix that.&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%2Fmckkddenwe96no6l4c0i.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%2Fmckkddenwe96no6l4c0i.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🏗️ Build time — Metro
&lt;/h2&gt;

&lt;p&gt;Metro is your &lt;strong&gt;only&lt;/strong&gt; build-time actor. It takes your JSX/TS files, transforms them to plain JavaScript, resolves imports, tree-shakes, and bundles everything.&lt;/p&gt;

&lt;p&gt;In dev mode → raw JS bundle.&lt;br&gt;
In production → Hermes pre-compiles it to bytecode before it ships inside the app.&lt;/p&gt;

&lt;p&gt;Think of Metro as Vite or Webpack, but purpose-built for React Native.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡ Runtime: JS layer — Hermes
&lt;/h2&gt;

&lt;p&gt;Hermes receives the bundle and executes it on device. The key difference from V8: &lt;strong&gt;Hermes is AOT (Ahead-of-Time)&lt;/strong&gt;, not JIT.&lt;/p&gt;

&lt;p&gt;By the time the app launches, the bytecode is already compiled. No parsing, no JIT warmup — execution starts immediately. That's where the startup speed win comes from.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Runtime: The bridge killer — JSI
&lt;/h2&gt;

&lt;p&gt;When JS needs to talk to native code, it used to go through the old bridge — JSON-serialized messages passed asynchronously. Slow, unpredictable, and batched.&lt;/p&gt;

&lt;p&gt;JSI (JavaScript Interface) replaces it entirely. JS now holds actual &lt;strong&gt;C++ host object references&lt;/strong&gt;. Calls can be synchronous or asynchronous, and there's no serialization cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  📐 Runtime: Native layer — Yoga + Fabric
&lt;/h2&gt;

&lt;p&gt;JSI feeds two parallel systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yoga&lt;/strong&gt; — a C++ flexbox layout engine (built by Meta). It runs on the shadow thread, computing x, y, width, and height from your style props — completely off the main thread.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fabric&lt;/strong&gt; — the new concurrent renderer (also C++). It builds the native view tree and replaces the old UIManager bridge.&lt;/p&gt;

&lt;p&gt;Both feed into the &lt;strong&gt;UI thread&lt;/strong&gt;, which commits the final render to iOS UIKit or Android ViewGroups. Pixels hit the screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The flow in one line
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your code → Metro → JS bundle → Hermes → JSI → Yoga + Fabric → Native views → Screen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new architecture isn't just a performance upgrade — it's a complete rethink of the JS ↔ native boundary.&lt;/p&gt;




&lt;p&gt;Drop a question below if any layer is still unclear 👇&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>javascript</category>
      <category>mobile</category>
      <category>architecture</category>
    </item>
    <item>
      <title>I Built a “Stateless” Frontend. Debugging It Nearly Broke Me.</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Sat, 09 May 2026 21:58:22 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/i-built-a-stateless-frontend-debugging-it-nearly-broke-me-5cmd</link>
      <guid>https://forem.com/khaledmsalem/i-built-a-stateless-frontend-debugging-it-nearly-broke-me-5cmd</guid>
      <description>&lt;p&gt;&lt;strong&gt;I believed “stateless = simple”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Like many frontend engineers, I bought into the idea early.&lt;/p&gt;

&lt;p&gt;No shared mutable state.&lt;br&gt;
No surprises.&lt;br&gt;
Just clean functions and predictable flows.&lt;/p&gt;

&lt;p&gt;So I decided to go all in and build a frontend that was as stateless as possible.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;It looked clean — until it wasn’t&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At first, everything felt disciplined.&lt;/p&gt;

&lt;p&gt;Then the app grew.&lt;/p&gt;

&lt;p&gt;And “stateless” slowly turned into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State duplicated across hooks&lt;/li&gt;
&lt;li&gt;State mirrored in the URL&lt;/li&gt;
&lt;li&gt;State cached, then reconstructed&lt;/li&gt;
&lt;li&gt;State synchronized across tabs&lt;/li&gt;
&lt;li&gt;State re‑derived after refreshes&lt;/li&gt;
&lt;li&gt;State invalidated in multiple places&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing was explicitly wrong.&lt;br&gt;
But nothing felt simple anymore.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Debugging became the real problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fixing a single UI bug meant answering questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this value stale or recomputed?&lt;/li&gt;
&lt;li&gt;Did an effect run twice?&lt;/li&gt;
&lt;li&gt;Is this coming from cache or network?&lt;/li&gt;
&lt;li&gt;Why does refreshing “fix” it?&lt;/li&gt;
&lt;li&gt;Where is the source of truth?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complexity wasn’t visible anymore — it was emergent.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The realization that changed everything&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Stateless didn’t remove state.&lt;/p&gt;

&lt;p&gt;It removed the ability to point at it.&lt;/p&gt;

&lt;p&gt;Instead of saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Here is the state.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I had to reason:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“If these things run in the correct order, state should emerge.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That works — until it doesn’t.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;State wasn’t the enemy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The real issue wasn’t having state.&lt;/p&gt;

&lt;p&gt;It was having implicit state that I wasn’t allowed to name.&lt;/p&gt;

&lt;p&gt;At scale, that turned every bug into a guessing game.&lt;/p&gt;

&lt;p&gt;That’s when I stopped asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How do I eliminate state?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And started asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How do I make state explicit, boring, and easy to reason about?”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;What I started doing differently&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I began experimenting with an alternative approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make state explicit&lt;/li&gt;
&lt;li&gt;Make lifecycle boundaries clear&lt;/li&gt;
&lt;li&gt;Treat persistence as first‑class&lt;/li&gt;
&lt;li&gt;Make “where this comes from” obvious&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result wasn’t flashy.&lt;/p&gt;

&lt;p&gt;It was boring.&lt;/p&gt;

&lt;p&gt;And for the first time, boring felt like progress.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Why this led to Ionify&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ionify exists because we got tired of pretending.&lt;/p&gt;

&lt;p&gt;Not pretending stateless is bad — but pretending it’s always simpler.&lt;/p&gt;

&lt;p&gt;Ionify doesn’t reject stateless ideas.&lt;br&gt;
It rejects hidden complexity.&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%2F45lem8bgeoyj2rasd72d.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%2F45lem8bgeoyj2rasd72d.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>architecture</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Frontend Build Tools Are Hitting a Wall</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Fri, 08 May 2026 20:14:19 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/frontend-build-tools-are-hitting-a-wall-l6o</link>
      <guid>https://forem.com/khaledmsalem/frontend-build-tools-are-hitting-a-wall-l6o</guid>
      <description>&lt;p&gt;For the last few years, frontend tooling has been obsessed with speed benchmarks.&lt;/p&gt;

&lt;p&gt;Cold start.&lt;br&gt;
HMR.&lt;br&gt;
Bundle time.&lt;br&gt;
Milliseconds everywhere.&lt;/p&gt;

&lt;p&gt;Webpack optimized bundling.&lt;br&gt;
Vite optimized development.&lt;br&gt;
Rolldown is optimizing Rollup itself.&lt;/p&gt;

&lt;p&gt;But almost every major tool still shares the same architectural assumption:&lt;/p&gt;

&lt;p&gt;The build starts from zero.&lt;/p&gt;

&lt;p&gt;That assumption worked when projects had hundreds of modules.&lt;br&gt;
It starts breaking when projects have 10K+ modules, monorepos, AI-generated code, and nonstop rebuild cycles.&lt;/p&gt;

&lt;p&gt;The problem is no longer “how fast can we transform code?”&lt;br&gt;
The real question is:&lt;/p&gt;

&lt;p&gt;Why are we transforming the same code again at all?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;That’s the idea behind &lt;strong&gt;Ionify&lt;/strong&gt; — a persistent frontend build engine built around a long-lived dependency graph and content-addressable storage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not a faster stateless runner.&lt;/p&gt;

&lt;p&gt;A system that remembers.&lt;/p&gt;

&lt;p&gt;Read more:&lt;br&gt;
&lt;a href="https://ionify.cloud/" rel="noopener noreferrer"&gt;Ionify Cloud&lt;/a&gt;&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%2Figjgqxgznmhilmq4eu2k.jpeg" 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%2Figjgqxgznmhilmq4eu2k.jpeg" alt=" " width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>webpack</category>
      <category>react</category>
    </item>
    <item>
      <title>Frontend Dev Tools in 2026: What Comes After Vite</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Wed, 06 May 2026 17:08:29 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/frontend-dev-tools-in-2026-what-comes-after-vite-52bl</link>
      <guid>https://forem.com/khaledmsalem/frontend-dev-tools-in-2026-what-comes-after-vite-52bl</guid>
      <description>&lt;p&gt;The frontend ecosystem has quietly moved on. Your dev tool strategy probably hasn't caught up yet.&lt;/p&gt;

&lt;p&gt;This is not a "Vite is dead" post. Vite is excellent. It earned its place. But in 2026, the baseline expectation for what a build engine &lt;em&gt;should do&lt;/em&gt; has shifted — and if you haven't noticed, it's probably costing your team time every single day without a single error message to show for it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Vite Architecture Was a Great Answer to a 2020 Problem
&lt;/h2&gt;

&lt;p&gt;When Vite arrived, it solved something real: Webpack was slow, config-heavy, and made development feel like punishment. Vite's answer was elegant — lean on native ES modules in the browser, skip the bundle during dev, use esbuild for speed.&lt;/p&gt;

&lt;p&gt;It worked. It still works.&lt;/p&gt;

&lt;p&gt;But there's a fundamental assumption baked into Vite's architecture that nobody talks about enough:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every build starts from zero.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;vite build&lt;/code&gt; or spin up &lt;code&gt;vite dev&lt;/code&gt;, here's what happens under the hood:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vite dev
  ↓
spin up esbuild/Rolldown
  ↓
plugin chain: TS plugin → JSX plugin → output
  ↓
main.tsx      → transform → output
utils.ts      → transform → output  
index.css     → transform → output
[every file]  → transform → output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next time you run it? &lt;strong&gt;Same thing. All of it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The TS plugin doesn't know the JSX plugin already processed a file yesterday. The bundler has no memory of which files changed since last time. The entire pipeline is stateless — by design.&lt;/p&gt;

&lt;p&gt;And here's the real cost that nobody measures: &lt;strong&gt;the React plugin hook.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every dev server start, every build — Vite needs &lt;code&gt;@vitejs/plugin-react&lt;/code&gt; to hook React into the pipeline. That plugin intercepts the transform chain, injects Fast Refresh runtime, handles JSX compilation, manages the HMR boundary detection. It runs on every file. Every start. Every time.&lt;/p&gt;

&lt;p&gt;On a small project, you don't feel it. On a project with thousands of modules and hundreds of dependencies, you feel it in your morning coffee going cold while you wait for the dev server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;On a +10K module, +25K deps React project: Vite build time — &lt;strong&gt;2.4 seconds&lt;/strong&gt; on a warm machine with aggressive caching config. Every. Single. Time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's not a bug. That's the architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Shift: From Stateless Pipeline to Persistent Engine
&lt;/h2&gt;

&lt;p&gt;The 2026 mental model for build tooling isn't "how fast can we transform files."&lt;/p&gt;

&lt;p&gt;It's "how much of this work can we &lt;em&gt;never do again&lt;/em&gt;."&lt;/p&gt;

&lt;p&gt;This is the insight Ionify was built on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ionify is built around a different assumption: most of the work you did last time is still valid.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of transforming files, Ionify &lt;em&gt;addresses&lt;/em&gt; them.&lt;/p&gt;

&lt;p&gt;Every module gets a content hash. Same content + same config = same hash = &lt;strong&gt;skip the transform entirely.&lt;/strong&gt; Not faster transforms. No transforms at all — for everything that hasn't changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module changes → BFS over reverse dependency index
→ find exactly which modules are affected
→ transform only those
→ everything else: CAS hit, served instantly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a 500-module project, changing one utility file might only invalidate 12 modules. Not all 500.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Four Layers of Memory
&lt;/h2&gt;

&lt;p&gt;This is where Ionify gets architecturally interesting. It doesn't just "cache" — it persists intelligence across four distinct layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1 — Module Transform Cache&lt;/strong&gt;&lt;br&gt;
Every transformed module stored by content hash. If your code didn't change, the transform never runs — not just in this session, but across branches, across teammates, across CI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2 — Deps Artifact Store&lt;/strong&gt;&lt;br&gt;
Your &lt;code&gt;node_modules&lt;/code&gt; dependencies, pre-optimized and partitioned by a &lt;code&gt;depsHash&lt;/code&gt;. A change in one library doesn't trigger full re-optimization of your entire dependency tree.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3 — Compression CAS&lt;/strong&gt;&lt;br&gt;
Brotli-11 + gzip-9 computed once, served forever. The compression work disappears after the first build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 4 — Chunk-Output CAS&lt;/strong&gt;&lt;br&gt;
Final build chunks stored by hash. In CI, if nothing changed, the output is assembled from cache — no rebuild at all.&lt;/p&gt;


&lt;h2&gt;
  
  
  React in 2026 Doesn't Need a Plugin to Start
&lt;/h2&gt;

&lt;p&gt;Here's what the Ionify config looks like for a React project:&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;defineConfig&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="s2"&gt;@ionify/ionify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/src/main.tsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;optimizeDeps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;sharedChunks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;vendorPacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;packSlimming&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;@vitejs/plugin-react&lt;/code&gt;. No plugin chain. No hook. React's JSX, Fast Refresh, and HMR are handled natively by the engine — because in 2026, a build engine that doesn't understand React natively is leaving performance on the table.&lt;/p&gt;

&lt;p&gt;The dev server and the production build use the same pipeline. One mental model. One config. No "why does this work in dev but break in build" mysteries.&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%2Fkohiuaocqm6f6vwp4wlg.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%2Fkohiuaocqm6f6vwp4wlg.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Numbers That Made Me Stop and Look Twice
&lt;/h2&gt;

&lt;p&gt;Same project. Same machine. Same code.&lt;/p&gt;

&lt;p&gt;Vite (Rolldown, optimized config) &lt;strong&gt;2.4s and Ionify 124ms.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ionify's warm build converges toward zero. The engine gets smarter the more you use it.&lt;/p&gt;

&lt;p&gt;For a team running builds dozens of times a day, across engineers, across CI pipelines — that's not a 10x improvement. &lt;strong&gt;That's a category difference.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  "But We've Got Caching Set Up in CI Already"
&lt;/h2&gt;

&lt;p&gt;I hear this. And it's worth being precise about what CI caching actually does vs. what Ionify does.&lt;/p&gt;

&lt;p&gt;CI caching (GitHub Actions cache, Turborepo, etc.) saves and restores directories between runs. It's filesystem-level. It works great for &lt;code&gt;node_modules&lt;/code&gt;. For build outputs, it's coarse — cache hit or cache miss, nothing in between.&lt;/p&gt;

&lt;p&gt;Ionify's CAS is module-level. A cache hit on a specific file's hash means that &lt;em&gt;exact transform&lt;/em&gt; never runs, regardless of what else changed. You can change 3 files in a 10,000-module project and Ionify will transform exactly those 3 files. Not the whole project. Not the changed files plus their folder. Exactly those 3.&lt;/p&gt;

&lt;p&gt;That's not a caching strategy. That's a different architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Cold Start (and What's Coming)
&lt;/h2&gt;

&lt;p&gt;The team is working on something interesting here — cross-project CAS sharing. The idea: when you &lt;code&gt;git clone&lt;/code&gt; a project and run &lt;code&gt;ionify dev&lt;/code&gt; for the first time, the engine checks a shared remote CAS. If your teammates already built those exact modules (same content hash), you pull the transform artifacts instead of rebuilding them.&lt;/p&gt;

&lt;p&gt;Warm builds for new engineers, from day one. The cold dead at the architecture level.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 2026 State of Dev Tooling
&lt;/h2&gt;

&lt;p&gt;The ecosystem has moved. The new baseline for a production build engine in 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Persistent&lt;/strong&gt; — the graph survives restarts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content-addressed&lt;/strong&gt; — transforms are tied to content, not time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unified&lt;/strong&gt; — dev and build use the same pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layered&lt;/strong&gt; — multiple levels of memory, not one cache flag&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vite gave us the escape from Webpack. Ionify is the next escape — from the assumption that stateless is the only way to be simple.&lt;/p&gt;

&lt;p&gt;Wise frontend teams in 2026 aren't asking "is my build fast enough." They're asking "how much of this build can we make permanent."&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



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

&lt;/div&gt;



&lt;p&gt;Docs and getting started: &lt;strong&gt;ionify.cloud&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The config is intentionally small. The intelligence is in the engine.&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%2F7o8c6e422x4qogm86o7x.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%2F7o8c6e422x4qogm86o7x.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>react</category>
      <category>vite</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The Real 2026 Frontend Revolution: Why Caching is Not Enough</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Tue, 05 May 2026 11:39:11 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/the-real-2026-frontend-revolution-why-caching-is-not-enough-ckl</link>
      <guid>https://forem.com/khaledmsalem/the-real-2026-frontend-revolution-why-caching-is-not-enough-ckl</guid>
      <description>&lt;p&gt;Everyone is hyped about Vite 8 and AI tools, but let’s talk about the real bottleneck: &lt;strong&gt;Stateful vs Stateless builds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most tools today suffer from "Past Amnesia". You clone a repo, and you wait. You change a branch, and you wait.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ionify&lt;/strong&gt; changes the game with a &lt;strong&gt;Persistence Graph and CAS-first architecture.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory, not Cache:&lt;/strong&gt; We built a memory layer that understands your project's journey.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: As your project grows, Ionify gets faster because it "learns" the relations between your modules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intelligence&lt;/strong&gt;: Try the &lt;/p&gt;

&lt;blockquote&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ionify analyze
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;command to see how the engine perceives your dependency graph.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are killing the "Cold Start" for good. Even for new clones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ionify.cloud/" rel="noopener noreferrer"&gt;https://ionify.cloud/&lt;/a&gt;&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%2Fg0pdp4weyohxcl9242u0.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%2Fg0pdp4weyohxcl9242u0.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>Your are still reprocessing the same modules. Every. Single. Time.</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Sun, 03 May 2026 10:22:37 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/your-are-still-reprocessing-the-same-modules-every-single-time-5fg2</link>
      <guid>https://forem.com/khaledmsalem/your-are-still-reprocessing-the-same-modules-every-single-time-5fg2</guid>
      <description>&lt;p&gt;You are still waiting 40 seconds for a dev server that restarted.&lt;/p&gt;

&lt;p&gt;Not because your machine is slow.&lt;br&gt;
Not because your project is too large.&lt;/p&gt;

&lt;p&gt;Because your build tool forgot everything it knew the moment the process exited&lt;/p&gt;

&lt;p&gt;The pattern every frontend team accepts automatically:&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;# restart dev server&lt;/span&gt;
vite

&lt;span class="c"&gt;# watch it reprocess 11,000 modules&lt;/span&gt;
&lt;span class="c"&gt;# that haven't changed since yesterday&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three wasted phases — resolution, transformation, optimization — on code that the tool already understood. Every restart. Every CI run. Every branch switch.&lt;br&gt;
The architectural flaw:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;build starts → analyzes deps → transforms modules → exits
build starts → analyzes deps → transforms modules → exits
build starts → analyzes deps → transforms modules → exits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No memory. No accumulation. Just stateless execution on repeat.&lt;/p&gt;

&lt;p&gt;What Ionify does instead:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;build starts → checks persistent graph → retrieves CAS result → done&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The dependency graph survives the process. The transformation result is stored by content hash. If the input hasn't changed — across restarts, across branches, across machines — the output is retrieved instantly.&lt;/p&gt;

&lt;p&gt;Real things this removes from your pipeline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Re-analysis of unchanged dependencies on every cold start&lt;/li&gt;
&lt;li&gt;Tree-shaking running from scratch on modules it processed an hour ago&lt;/li&gt;
&lt;li&gt;CI rebuilding what the previous run already computed&lt;/li&gt;
&lt;li&gt;The 40-second gap between "I saved the file" and "I see the change"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What this gives you instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sub-100ms warm rebuilds on 11,000+ modules&lt;/li&gt;
&lt;li&gt;One persistent graph shared across dev and production&lt;/li&gt;
&lt;li&gt;Dep optimization that lives from the first cold start and never repeats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How many seconds does your build tool spend reprocessing code that hasn't changed?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create ionify@latest

⭐ &lt;span class="o"&gt;[&lt;/span&gt;github.com/ionify]&lt;span class="o"&gt;(&lt;/span&gt;github.com/ionifyjs/ionify&lt;span class="o"&gt;)&lt;/span&gt; · &lt;span class="o"&gt;[&lt;/span&gt;ionify.cloud]&lt;span class="o"&gt;(&lt;/span&gt;https://ionify.cloud/&lt;span class="o"&gt;)&lt;/span&gt;
&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%2F0qpos460d6c6r2polmxr.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%2F0qpos460d6c6r2polmxr.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>react</category>
      <category>webpack</category>
    </item>
    <item>
      <title>Tree-Shaking is Over! Are you done with the limitations and repetition of traditional tree-shaking?</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Sat, 02 May 2026 08:37:11 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/tree-shaking-is-over-are-you-done-with-the-limitations-and-repetition-of-traditional-tree-shaking-10ap</link>
      <guid>https://forem.com/khaledmsalem/tree-shaking-is-over-are-you-done-with-the-limitations-and-repetition-of-traditional-tree-shaking-10ap</guid>
      <description>&lt;p&gt;If you've used Vite, you know tree-shaking. It's fast, it's smart, and it runs on every single build — from scratch — every time. That's the part nobody talks about.&lt;/p&gt;

&lt;p&gt;Today I want to introduce something we've been quietly building inside Ionify: &lt;strong&gt;packSlimming&lt;/strong&gt;. It's our architectural answer to what tree-shaking actually costs at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem with tree-shaking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tree-shaking is a per-build operation. Every time your build tool runs, it re-analyzes your entire dependency. That analysis disappears when the process exits. Next run? Start over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;packSlimming: analysis that lives&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;packSlimming is backed by Ionify's persistent graph and CAS layer. Here's what that means concretely:&lt;/p&gt;

&lt;p&gt;From your very first cold start, packSlimming analyzes your deps and stores the result. Every subsequent run — whether it's a dev server restart, a production build, or a CI run on the same branch — reuses that analysis. Your deps optimization is live from day one and never repeated unless something actually changes.&lt;/p&gt;

&lt;p&gt;Ionify isn't trying to be the fastest version of what already exists. It's a different model entirely — a build engine that accumulates intelligence instead of discarding it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create ionify@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⭐ github.com/ionifyjs/ionify &lt;br&gt;
👉 &lt;a href="https://ionify.cloud/" rel="noopener noreferrer"&gt;ionify.cloud&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&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%2Fzqmsb9ivzbd3i76arv1m.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%2Fzqmsb9ivzbd3i76arv1m.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>frontend</category>
    </item>
    <item>
      <title>We fixed a subtle HMR bug that was showing false build errors in Ionify</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Wed, 29 Apr 2026 22:36:56 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/we-fixed-a-subtle-hmr-bug-that-was-showing-false-build-errors-in-ionify-30nn</link>
      <guid>https://forem.com/khaledmsalem/we-fixed-a-subtle-hmr-bug-that-was-showing-false-build-errors-in-ionify-30nn</guid>
      <description>&lt;p&gt;Small but satisfying fix shipped today. Worth writing up because the root cause is the kind of bug that's easy to misread as a client-side problem.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;What developers were seeing&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
During React Fast Refresh edits, Ionify would sometimes flash an Ionify Build Error overlay — even when the source edit was valid and the change was already visible in the UI. Confusing, because the build wasn't actually broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What was actually happening&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The HMR server was treating each queued update as single-consumer state. The moment a client hit /apply for a given update ID, the server consumed and deleted that update.&lt;/p&gt;

&lt;p&gt;In practice this meant: if multiple clients were connected, if an apply was attempted more than once, or if refresh timing raced against the same update ID — any attempt after the first would receive 404 Update not found. The client had no way to distinguish that from a real build failure, so it surfaced the error overlay.&lt;/p&gt;

&lt;p&gt;The edit was fine. The UI had already updated. But the overlay said otherwise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Pending HMR updates are now kept reusable for a short TTL instead of being deleted on first apply. Updates expire by age to keep memory bounded — so you don't accumulate stale state indefinitely, but valid late-arriving apply attempts no longer hit a 404.&lt;/p&gt;

&lt;p&gt;Full issue and diff: &lt;a href="https://github.com/ionifyjs/ionify/issues/2" rel="noopener noreferrer"&gt;https://github.com/ionifyjs/ionify/issues/2&lt;/a&gt;&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%2Fll1hqcgiqn3r0va9avlv.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%2Fll1hqcgiqn3r0va9avlv.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ionify</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>In 2026 everyone is talking about AI-powered build tools.</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Tue, 28 Apr 2026 09:05:36 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/in-2026-everyone-is-talking-about-ai-powered-build-tools-2k4l</link>
      <guid>https://forem.com/khaledmsalem/in-2026-everyone-is-talking-about-ai-powered-build-tools-2k4l</guid>
      <description>&lt;p&gt;In 2026 everyone is talking about AI-powered build tools.&lt;/p&gt;

&lt;p&gt;But nobody is talking about the real bottleneck.&lt;/p&gt;

&lt;p&gt;Your AI assistant generates code in milliseconds.&lt;br&gt;
Then your build tool spends 40 seconds reprocessing modules it saw yesterday.&lt;/p&gt;

&lt;p&gt;The bottleneck isn't your AI. It's your stateless build pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ionify&lt;/strong&gt; fixes the part everyone forgot:&lt;br&gt;
→ Persistent dependency graph&lt;br&gt;
→ CAS: every transform stored by content hash&lt;br&gt;
→ 100ms warm rebuilds on 11k+ modules&lt;/p&gt;

&lt;p&gt;Your AI deserves a build engine that keeps up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ionify&lt;/strong&gt; is a Rust-powered build engine that approaches this differently. Instead of optimizing the stateless runner, we built a persistent engine.&lt;/p&gt;

&lt;p&gt;⭐ github.com/ionifyjs/ionify&lt;br&gt;
🌐 ionify.cloud&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%2F50jpzgoy5ipgrbd3d37s.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%2F50jpzgoy5ipgrbd3d37s.png" alt=" " width="800" height="533"&gt;&lt;/a&gt; &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>react</category>
    </item>
    <item>
      <title>Why your build tool has amnesia — and how we fixed it with a persistent graph and CAS</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Mon, 27 Apr 2026 14:39:43 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/why-your-build-tool-has-amnesia-and-how-we-fixed-it-with-a-persistent-graph-and-cas-1p75</link>
      <guid>https://forem.com/khaledmsalem/why-your-build-tool-has-amnesia-and-how-we-fixed-it-with-a-persistent-graph-and-cas-1p75</guid>
      <description>&lt;p&gt;Every few years, the frontend community rallies around a faster build tool.&lt;br&gt;
Grunt gave way to Webpack. Webpack gave way to Parcel, then Rollup, then Vite. Each one measurably faster. Each one celebrated. And yet, there's a problem none of them ever touched: they all start from zero, every single time.&lt;/p&gt;

&lt;p&gt;This isn't a performance problem. It's an architectural one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The real issue: stateless pipelines&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a build process exits — whether that's a dev server restart, a CI run, or a branch switch — everything it computed disappears. The dependency graph it built? Gone. The transforms it ran? Gone. The structural knowledge of your project it accumulated? Gone.&lt;/p&gt;

&lt;p&gt;We call this &lt;strong&gt;Past Amnesia.&lt;/strong&gt; And on large projects, it's brutally expensive.&lt;/p&gt;

&lt;p&gt;On a large-scale with 25,000+ dependencies, a cold start with today's best tools can cost 40–90 seconds. even vite-8 cost build 2.4 seconds. Not because the machine is slow. Because the tool is reprocessing modules it already analyzed last run, last hour, last week — with no memory of what it already knew.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we built: Ionify&lt;/strong&gt;&lt;br&gt;
Ionify is a Rust-powered build engine that approaches this differently. Instead of optimizing the stateless runner, we built a persistent engine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Persistent Dependency Graph&lt;/strong&gt;&lt;br&gt;
Module relationships are stored and survive process restarts. When you change a file, the engine re-enters the graph at the changed node — not at zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content-Addressable Storage (CAS)&lt;/strong&gt;&lt;br&gt;
Every transformed module is stored by the hash of its input. If the input hasn't changed — across restarts, across branches, across machines — the transform is never repeated. The result is retrieved instantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dual-hash isolation&lt;/strong&gt;&lt;br&gt;
A versionHash ties your graph and CAS to your current configuration. A depsHash partitions optimized dependencies so a single library update doesn't invalidate everything else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hybrid transform engine&lt;/strong&gt;&lt;br&gt;
OXC handles the fast path. SWC provides a resilience fallback.Same pipeline, both engines, no ecosystem compromises.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unified dev + prod&lt;/strong&gt;&lt;br&gt;
Same engine, same semantics across both environments. The "works in dev, breaks in prod" class of bugs disappears by design.&lt;/p&gt;

&lt;p&gt;The result&lt;br&gt;
sub-100ms warm rebuilds on projects with 11,000+ internal modules. Not a benchmark trick — the natural outcome of a system that stops repeating work it already did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters in 2026&lt;/strong&gt;&lt;br&gt;
Everyone is talking about AI-assisted development. AI generates code in seconds. But if your build pipeline costs 40 seconds every restart, you haven't solved the bottleneck — you've just moved it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ionify&lt;/strong&gt; is the infrastructure layer that lets the rest of your toolchain actually compound. A build engine that gets smarter with every run, instead of forgetting everything when the process exits&lt;/p&gt;

&lt;p&gt;Try it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create ionify@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scaffolds a fully configured environment in seconds.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌐 &lt;a href="https://dev.tourl"&gt;ionify.cloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;⭐ &lt;a href="https://dev.tourl"&gt;github.com/ionifyjs/ionify&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy to answer questions about the graph model, the CAS design, or the OXC+SWC hybrid decision in the comments&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%2F3dck1va8jitekg3bz1ux.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%2F3dck1va8jitekg3bz1ux.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>rust</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Why Your Build Tool Keeps Rebuilding Everything (And How I Fixed It)</title>
      <dc:creator>KhaledSalem</dc:creator>
      <pubDate>Sat, 25 Apr 2026 11:51:44 +0000</pubDate>
      <link>https://forem.com/khaledmsalem/why-your-build-tool-keeps-rebuilding-everything-and-how-i-fixed-it-553h</link>
      <guid>https://forem.com/khaledmsalem/why-your-build-tool-keeps-rebuilding-everything-and-how-i-fixed-it-553h</guid>
      <description>&lt;p&gt;Let’s be honest.&lt;/p&gt;

&lt;p&gt;Every time you run a build, your tool forgets everything it did before.&lt;/p&gt;

&lt;p&gt;Even if nothing changed.&lt;/p&gt;

&lt;p&gt;Even if you just ran it seconds ago.&lt;/p&gt;

&lt;p&gt;That’s not optimization.&lt;br&gt;
That’s amnesia.&lt;/p&gt;

&lt;p&gt;After 10+ years working in frontend, I got tired of this model — so I built Ionify.&lt;/p&gt;

&lt;p&gt;I tested a real project with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;11K+ modules&lt;/li&gt;
&lt;li&gt;25K+ dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vite:&lt;br&gt;
→ ~2.4s&lt;/p&gt;

&lt;p&gt;Ionify:&lt;br&gt;
→ 124ms&lt;/p&gt;

&lt;p&gt;The difference isn’t faster compilation.&lt;/p&gt;

&lt;p&gt;The difference is memory.&lt;/p&gt;

&lt;p&gt;Ionify uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Persistent dependency graph&lt;/li&gt;
&lt;li&gt;Content-addressable storage (CAS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of rebuilding everything,&lt;br&gt;
it reuses everything.&lt;/p&gt;

&lt;p&gt;If you're curious, try it yourself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ionify.cloud/" rel="noopener noreferrer"&gt;https://ionify.cloud/&lt;/a&gt;&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%2F8qj7pzq7ku2xmgtzceh9.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%2F8qj7pzq7ku2xmgtzceh9.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
