<?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: OzmaKa</title>
    <description>The latest articles on DEV Community by OzmaKa (@ozma).</description>
    <link>https://dev.to/ozma</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%2F1439915%2Fa4f05559-c02c-4497-82e0-07e20f5193a5.jpg</url>
      <title>DEV Community: OzmaKa</title>
      <link>https://dev.to/ozma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ozma"/>
    <language>en</language>
    <item>
      <title>I Built a React Performance Analyzer as a Graduation Project — It Got 2,700+ Downloads from 25 Countries</title>
      <dc:creator>OzmaKa</dc:creator>
      <pubDate>Thu, 09 Jul 2026 11:15:04 +0000</pubDate>
      <link>https://dev.to/ozma/i-built-a-react-performance-analyzer-as-a-graduation-project-it-got-2700-downloads-from-25-3kj5</link>
      <guid>https://dev.to/ozma/i-built-a-react-performance-analyzer-as-a-graduation-project-it-got-2700-downloads-from-25-3kj5</guid>
      <description>&lt;p&gt;&lt;em&gt;A story about building something real, shipping it, and watching strangers use it.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;A few months ago, my team and I were looking for a graduation project idea. We wanted to build something that actually solved a real problem — not a to-do app, not a clone of something that already existed.&lt;/p&gt;

&lt;p&gt;We landed on a question that every React developer eventually asks:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Why is my app slow, and where exactly is the problem?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer is usually scattered across three or four different tools. ESLint catches some code smells. Lighthouse measures some runtime metrics. React DevTools shows component re-renders. None of them talk to each other, and none of them give you a single, prioritized list of things to fix.&lt;/p&gt;

&lt;p&gt;So we built one tool that does all of it at once. We called it &lt;strong&gt;React Doctor&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What React Doctor Does
&lt;/h2&gt;

&lt;p&gt;React Doctor is a CLI tool written in TypeScript that runs in Node.js. You point it at any React project and run one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;react-doctor full ./my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It then executes four steps automatically:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Static Analysis
&lt;/h3&gt;

&lt;p&gt;It reads every &lt;code&gt;.jsx&lt;/code&gt; and &lt;code&gt;.tsx&lt;/code&gt; file in your project and parses them into an Abstract Syntax Tree using Babel. Nine specialized detectors walk the tree looking for real problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;useEffect&lt;/code&gt; hooks with no dependency array (infinite loop risk)&lt;/li&gt;
&lt;li&gt;Components missing &lt;code&gt;React.memo()&lt;/code&gt; that would benefit from it&lt;/li&gt;
&lt;li&gt;Prop drilling through multiple component layers&lt;/li&gt;
&lt;li&gt;Inline functions recreated on every render&lt;/li&gt;
&lt;li&gt;Dead code and unused imports&lt;/li&gt;
&lt;li&gt;Oversized components (300+ lines)&lt;/li&gt;
&lt;li&gt;Missing &lt;code&gt;key&lt;/code&gt; props in lists&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;console.log&lt;/code&gt; calls left in production code&lt;/li&gt;
&lt;li&gt;Large style objects defined directly in JSX&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every issue comes back with the exact file, line number, and severity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Runtime Profiling
&lt;/h3&gt;

&lt;p&gt;This is where it goes further than a linter ever could. React Doctor spins up your dev server, launches a headless Chrome instance through Puppeteer, and injects a hook directly into React's DevTools global hook — before the app even renders.&lt;/p&gt;

&lt;p&gt;From there it captures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All 5 Core Web Vitals (LCP, FCP, CLS, INP, TTFB)&lt;/li&gt;
&lt;li&gt;React's actual commit durations&lt;/li&gt;
&lt;li&gt;Which components re-rendered and how many times&lt;/li&gt;
&lt;li&gt;DOM node count, memory usage, heaviest asset&lt;/li&gt;
&lt;li&gt;JavaScript errors captured during load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It can also simulate mobile viewports, CPU throttling, and slow network conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;react-doctor full ./my-app &lt;span class="nt"&gt;--mobile&lt;/span&gt; &lt;span class="nt"&gt;--cpu&lt;/span&gt; 4 &lt;span class="nt"&gt;--throttle&lt;/span&gt; slow4g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 — Rule Engine
&lt;/h3&gt;

&lt;p&gt;This is the part I'm proudest of architecturally. 25 rules split into three categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static rules&lt;/strong&gt; — fire on code patterns alone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime rules&lt;/strong&gt; — fire on performance metrics alone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross rules&lt;/strong&gt; — require BOTH conditions to be true simultaneously&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A cross rule might only fire when a component is missing &lt;code&gt;React.memo()&lt;/code&gt; AND was measured re-rendering more than 5 times in the actual browser session. Neither the static analyzer nor the profiler alone would catch that pattern. Combining them does.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — Report Compiler
&lt;/h3&gt;

&lt;p&gt;Everything gets merged into four JSON files saved in &lt;code&gt;.react-doctor/&lt;/code&gt; inside your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.react-doctor/
├── staticreport.json
├── runtimereport.json
├── suggestions.json
└── finalreport.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Dashboard
&lt;/h2&gt;

&lt;p&gt;We also built a backend (Express + SQLite) and a dashboard. Running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;react-doctor full ./my-app &lt;span class="nt"&gt;--upload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Automatically starts the backend if it isn't running, uploads the report, and opens the dashboard in your browser — straight to that specific report.&lt;/p&gt;

&lt;p&gt;The dashboard shows Web Vitals as color-coded cards, issues filterable by severity, screenshots taken at key load moments, and a score history chart so you can watch your fixes actually move the needle across multiple runs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Challenges
&lt;/h2&gt;

&lt;p&gt;The bugs we hit were more educational than the features we built:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-platform path hell.&lt;/strong&gt; Windows and Linux handle Chrome paths, shell processes, and file paths completely differently. What worked on one broke silently on the other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript compilation target.&lt;/strong&gt; ts-node defaults to ES3. That caused a &lt;code&gt;__spreadArray is not defined&lt;/code&gt; error at runtime that took real debugging to trace. Fixed by explicitly setting &lt;code&gt;target: "ES2020"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The output path bug.&lt;/strong&gt; On Linux, the final report was writing to the global npm installation directory instead of the user's project folder. Fixed by passing &lt;code&gt;outputDir&lt;/code&gt; explicitly through the entire pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API URL mismatch.&lt;/strong&gt; Our CLI was posting to &lt;code&gt;/api/report/upload&lt;/code&gt; (singular) but the backend served &lt;code&gt;/api/reports/upload&lt;/code&gt; (plural). This caused a 401 error that looked like an auth problem but was actually a routing problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQLite and screenshots.&lt;/strong&gt; Storing screenshots as base64 strings inside SQLite made the database enormous. We switched to saving them as separate PNG files and storing only the path — obvious in retrospect, not obvious at 2am.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Number That Surprised Us
&lt;/h2&gt;

&lt;p&gt;We published to npm as &lt;code&gt;react-doctor-cli-dev&lt;/code&gt;. We shared it with our classmates, posted it on LinkedIn, and moved on to other things.&lt;/p&gt;

&lt;p&gt;Then the downloads started coming in from people we didn't know.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2,730+ downloads. 25+ countries.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;United States (~764), Germany (~218), United Kingdom (~191), China (~164), France (~137) — and 20 more countries.&lt;/p&gt;

&lt;p&gt;We didn't run ads. We didn't post on Reddit. We didn't do a Product Hunt launch. The downloads came from developers finding the package organically on npm and deciding it was worth trying.&lt;/p&gt;

&lt;p&gt;That number means more to me than any grade.&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; &lt;span class="nt"&gt;-g&lt;/span&gt; react-doctor-cli-dev
react-doctor full ./your-react-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Requires Node.js 18+ and Chrome. Works on Windows, Linux, and macOS.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📦 &lt;a href="https://www.npmjs.com/package/react-doctor-cli-dev" rel="noopener noreferrer"&gt;npm package&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐙 &lt;a href="https://github.com/softar-dev/React_Doctor" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🌐 &lt;a href="https://react-doctor-cli.web.app" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A Small Ask
&lt;/h2&gt;

&lt;p&gt;React Doctor is completely free and open source. If it saves you time, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⭐ Starring the repo on GitHub — it helps more developers find it&lt;/li&gt;
&lt;li&gt;☕ &lt;a href="https://react-doctor-cli.web.app/support" rel="noopener noreferrer"&gt;Supporting the project&lt;/a&gt; — any amount helps cover domain costs and keeps development going&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built by Oussamah Kabalan, Shaheen Sharba — software engineering students at Homs University, Syria.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>react</category>
    </item>
  </channel>
</rss>
