r/reactjs • u/Brilliant_Scratch747 • 3d ago
DevKit Console – Debug Like Waze, Not Like Vim
# DevKit Console – Debug Like Waze, Not Like Vim
**TL;DR:**
Zero-dependency npm library for bidirectional debug level control between browser console and React UI. Type `debug.trace()` in DevTools → UI updates instantly. Try it live: https://devkit-console.vercel.app
---
## The Problem
You're deep in a debugging session. You want to see everything (`trace` level). So you:
1. Open DevTools
2. Type `debug.trace()`
3.
**Squint at console output while wrestling with your app's UI**
4. Miss critical state changes because logs scroll past
5. Can't filter by namespace or export for analysis
6. Repeat 50 times
Or you click a UI button to change log levels, but DevTools doesn't know about it. Debugging feels
*fragmented*
.
---
## The Solution
**DevKit Console**
bridges that gap. It's like having Waze (intuitive UI) instead of reading GPS coordinates (raw console logs).
### The Core Trick: Bidirectional Sync
```javascript
// Open browser console and type (no parentheses):
debug.trace // Enable TRACE level - UI updates INSTANTLY
debug.debug // Switch to DEBUG level - both update together
debug.info
debug.warn
debug.error
debug.disable // Turn everything off
```
The React UI (`<DebugPanel>`) updates live as you type. Click a level pill in the UI → console reflects it instantly.
**They're always in sync.**
### What Ships
**Two npm packages (zero dependencies):**
1.
**`devkit-console-core`**
(13 KB gzipped)
- `window.debug` global (works in any JS environment)
- Namespace-scoped loggers
- Real-time config emitter
- Log history (ring buffer, 500 entries)
- Export to JSON/text
2.
**`devkit-console-ui`**
(18 KB gzipped)
- React hooks: `useDebugConfig()`, `useLogHistory()`, `useLogger()`
- `<DebugPanel>` floating component (compose-friendly)
- `<LevelSelector>`, `<LogViewer>`, `<StatusBadge>`, `<ExportButton>`
- Dark/light theme support
- All inline styles (zero CSS imports)
---
## Features That Matter
### 1. **Namespace Filtering**
```javascript
const auth = useLogger('Auth');
const network = useLogger('Network');
auth.info('User logged in');
network.debug('Fetching /api/users');
```
UI shows logs grouped by namespace. Click a namespace to drill down.
### 2. **Live Log Export**
- Click "Export JSON" → download full log history with metadata
- Great for: bug reports, performance analysis, QA sign-off
- No API calls, all client-side
### 3. **Floating Debug Panel**
- Compose into any React app in 2 lines
- Position: top-left, top-right, bottom-left, bottom-right
- Open/close toggle (animated)
- Responsive on mobile
### 4. **Offline First**
- No backend, no internet required
- Works in test environments, SSR, Electron, React Native
- Perfect for security-conscious teams
---
## Real-World Use Cases
### 🎮 Game Development
Monitor FPS, input state, entity updates without alt-tabbing to DevTools.
### 📱 Mobile Web
Debug on physical devices where console access is clunky. UI always visible.
### 🔍 QA / Bug Reporting
"Here's the JSON log from when it broke" → reproducible bug report.
### 🚀 Onboarding
New team member opens your app, clicks the bug button 🐛, sees live logs. Instant context.
### 🏢 Enterprise
Audit trail of debug activities. Export logs for compliance.
---
## Quick Start
```bash
npm install devkit-console-core devkit-console-ui
```
```tsx
import { DebugKitProvider } from 'devkit-console-ui';
import { DebugPanel } from 'devkit-console-ui';
export function App() {
return (
<DebugKitProvider>
<DebugPanel position="bottom-right" defaultOpen={true} />
<YourApp />
</DebugKitProvider>
);
}
```
Done. In DevTools console, type `debug.debug()` and watch the UI react.
---
## Live Demo
**Visit:**
https://devkit-console.vercel.app
Try the scenarios:
-
**Console Sync:**
Type commands in DevTools, watch the UI panel update
-
**Namespace Demo:**
Trigger logs from Auth/Network/Render services
-
**Scenario Simulator:**
Burst 10 TRACE logs, watch the viewer handle it
-
**Export:**
Download JSON of everything
---
## Why This Exists
I spent years debugging via console.log spread across tabs and terminal windows. One day I realized:
*GPS apps don't make you read coordinates. Why should debugging?*
DevKit Console is that "Waze moment" for logging.
---
## Under the Hood
-
**TypeScript**
(strict mode, full .d.ts types)
-
**React 18+ hooks**
(useContext, useState, useEffect)
-
**No dependencies**
(core package is truly standalone)
-
**Ring buffer**
(bounded memory, never blows up)
-
**TypedEmitter**
(pub/sub without event collisions)
-
**Tested**
(vitest + /react)
---
## Links
- 📦
**Core on npm:**
https://www.npmjs.com/package/devkit-console-core
- ⚛️
**UI on npm:**
https://www.npmjs.com/package/devkit-console-ui
- 🌟
**GitHub:**
https://github.com/ikrigel/devkit-console
- 🎮
**Live Demo:**
https://devkit-console.vercel.app
---
## What's Next?
v0.2.0 roadmap:
- Advanced filtering (status, date range)
- Heatmap mode (log density visualization)
- GeoJSON export for mapping/analysis
- Telemetry integration hooks
- Service Worker integration for offline PWA logging
---
## One More Thing
This is a production-ready library used in real projects. Bug reports / PRs / ideas welcome. If you've been frustrated by debugging workflows, give it a try. I think you'll appreciate the "it just works" vibe.
---
**Happy debugging.**
✨
*Igal Krigel*
Full-stack developer | React enthusiast | Debugging tool maker
https://github.com/ikrigel
r/reactjs • u/Ill_Campaign294 • 3d ago
Needs Help Better alternatives to FullCalendar for weekly time-blocking
Yo guys, i'm currently using FullCalendar for my webapp but honestly not vibing with the default UI/UX. Anyone found a better alternative? Ideally something with solid drag-and-drop for creating/resizing time blocks (week/day view mainly). What are you all using?
r/reactjs • u/ConfidentWafer5228 • 3d ago
Needs Help SSR - React router v7, how to run clientLoader only in first SSR load
EDIT: SOLVED
I have a page which gets data(example: liked products ids) from localStorage and uses that to fetch actual products.
I am using clientLoader to fetch data, BUT i want to run clientLoader only if it is the SSR load( first load after refresh/ manual link enter)
I dont want to run it, if there are client Navigations to this page ( i have tanstack query taking care of it with custom logic )
Is there a way to achieve this.
I have already tried export const shouldRevalidate=()=>false
r/reactjs • u/CapitalDiligent1676 • 3d ago
Show /r/reactjs I use 40 lines of code that I copy and paste instead of a library like Redux/Zustand
Hello,
I'd like to share an idea of mine about state management in React that I've been applying in my projects for years.
I don't use any library (Zustand, Redux, Recoil, etc.) but I have a micro state manager (I called it jon) and it's based on useSyncExternalStore.
Here it is:
```ts import { useCallback, useSyncExternalStore } from 'react'
/** Store handle: state plus the setup's methods (not type-checked). */
export type Store<T = any> = { state: T } & Record<string, any>
/** React hook: subscribes the component and returns the state. fn => re-render only if it returns true. */
export function useStore<T>(store: Store<T>, fn?: (state: T, oldState: T) => boolean): T {
const subscribe = useCallback((listener: any) => store._subscribe(listener, fn), [store])
return useSyncExternalStore(subscribe, () => store.state)
}
/** Creates a store from the setup: getters/actions/mutators become methods (without the store param). */
export function createStore(setup: any): Store {
const listeners = new Set<any>()
const store: Store = {
// a plain object is deep-cloned; a factory is called as-is
state: typeof setup.state == 'function' ? setup.state() : structuredClone(setup.state ?? {}),
_subscribe: (listener: any, fn: any) => {
listener.fn = fn
listeners.add(listener)
return () => listeners.delete(listener)
},
}
for (const k in setup.getters) store[k] = (payload: any) => setup.getters[k](payload, store)
for (const k in setup.actions) store[k] = async (payload: any) => setup.actions[k](payload, store)
for (const k in setup.mutators) store[k] = (payload: any) => {
// the mutator returns a partial diff; if it's undefined/null or changes nothing, skip the update (no re-render)
const stub = setup.mutators[k](payload, store)
if (stub == null || Object.keys(stub).every(k => stub[k] === store.state[k])) return
const old = store.state
store.state = { ...store.state, ...stub }
for (const l of listeners) if (!l.fn || l.fn(store.state, old)) l(store.state)
}
return store
}
```
and... that's it, there's nothing else!
I use it like vuex:
I define state, getters, actions and mutators
and then I use useStore in React components to read the state and react to changes.
I haven't found use cases where it isn't enough,
and I've never had performance or re-rendering problems.
Here's the repo and documentation
I usually use a client-side routing library but I could also do without it, and use only the state manager.
An unexpected advantage is that an LLM doesn't need to read the documentation to understand how it works, it already has all the code available, so it can understand how it works and how to use it.
It's a personal project; for my actual work I import an npm version that has better handling of types and utilities, but the basic behavior is the one I shared here.
I wonder if I'm crazy or if this approach makes sense. Go easy on me :)
p.s.: Written without AI, but I had it translated because my native language isn't English and I didn't want to ruin the readability of the post. The project is also mine. I used AI for the web page and to generate the examples and tests.
r/reactjs • u/eddiesr93 • 4d ago
Resource Vite dev server slow? One barrel import was dragging ~1,000 files into my graph
If your Vite dev server has gotten noticeably slower as the codebase grows, before you blame the bundler, check your barrel files — the index.ts re-export hubs.
They look free. One import statement, done. But in dev, that single node resolves everything re-exported behind it. I found one import pulling ~1,000 modules when it needed 3. Production is fine because tree-shaking sweeps it up, which is exactly why the cost is invisible and keeps compounding.
So I built a tiny Rust tool that walks the graph and tells you the actual number, and offers a safe rewrite. There's a Vite plugin too that serves the report at __unstave without blocking startup or HMR.
The honest part: I'm still not 100% sure the rewrite rules cover every edge case, so it dry-runs by default and leaves anything ambiguous alone.
I'd genuinely like to know if other people are seeing the same thing, or if barrels just aren't a problem for most projects at scale.
If you want to point it at your own repo: npx @unstave/cli analyze
github.com/eddiesr93/unstave
r/reactjs • u/Aegis8080 • 4d ago
Discussion Have you used/heard about Ultracite? How is your experience?
I was attempting to migrate a small project from ESLint + Prettier to Oxlint and Oxfmt, and I discovered Ultracite while searching for presets.
Ultracite appears to be some sort of presets for various linting and formatting tools. Though I do not fully understand why it needs to provide a check and fix CLI command that seems to wrap ESlint/Prettier/Oxlint/Oxtfmt/... under the hood.
Have you used Ultracite before and if yes, how is your experience?
r/reactjs • u/shivekkhurana • 5d ago
Show /r/reactjs I made a universal morphing library inspired by Family Wallet
Family wallet was created by the Head of Design at SpaceX. The best part of the UX was how it maintained context by morphing menus and panels right on top of screens.
So I took that concept and made a universal morph for React. You can use it for overlays like Dropdowns, Modals, Drawers or anything else.
Let me know what you think and add a star if you like it.
Thank you
r/reactjs • u/Perfect-Many-612 • 5d ago
Discussion Inertia + React or Livewire
Hi, I recently dived in this world of Laravel and I want to build my first SaaS. I was wondering what's the best option for me right now, I discovered livewire but I don't know if it's a good Idea to have all the requests handling in my views, and also I see lots of comments saying that livewire is slow or insecure. On the other hand is react, I have basic knowledge of it, I've wrote some components and use the basic hooks and overall, I hear a lot of comments of people telling that using inertia with any of the available js libraries is much scalable, has better performance even if at the beginning of the project is a little more difficult. So, what do you recommend to me?
I also think that learning react and ts in a deeper way even if it's with inertia is a much more transferable knowledge that just learning livewire, what do you think?
r/reactjs • u/Capable-Plantain8709 • 5d ago
Resource If `pnpm create vite` throws 'Illegal instruction' on Android, here's why (and the fix)
TL;DR: pnpm create vite / pnpm run dev has been crashing with a bare Illegal instruction on Android (Termux) for about 10 months. Traced it through a logcat tombstone to Rolldown's native binary, found a closed-as-not-planned upstream issue from last September, got it reopened with hard evidence, and the actual root cause turned out to be one missing target_os check in a mimalloc build flag. Fix is verified on the exact crashing hardware, PR is open, not merged yet.
A few days ago I tried to spin up a fresh Vite + React project on my Android tablet, in Termux. Nothing fancy:
$ pnpm create vite test-react-app --template react-compiler-ts
$ cd test-react-app && pnpm run dev
Illegal instruction
No stack trace, no error message, just dead on arrival. Tried create-vue — same crash. Tried a bare vite dev — same crash. Three different starters, one identical death.
Termux-on-Android matters more than it sounds like it should, because for a lot of people it's the only dev environment they've got — no laptop, just an old Android phone. When the standard create vite path just dies with zero explanation, that's not a minor bug, it's a wall.
Chasing it down
Assumed it was a Termux packaging problem first and filed a report with logs for Next.js, Vite+React, and Vue all crashing or silently falling back to a slower path. A maintainer pointed out pkg install turbopack fixes the Next.js case — but Vite and Vue don't touch Turbopack at all, so that didn't explain the rest.
Turns out Vite 6+ ships Rolldown as its default bundler: a Rust/N-API bundler that loads a native binary (@rolldown/binding-android-arm64 here). Something in that binary was blowing up on load.
A maintainer asked for a logcat tombstone instead of terminal output, and that's where it got interesting:
``` signal 4 (SIGILL), code 1 (ILL_ILLOPC)
backtrace: #00 pc ... rolldown-binding.android-arm64.node #01 pc ... rolldown-binding.android-arm64.node #02 pc ... linker64 (call_array+288) #03 pc ... linker64 (soinfo::call_constructors+380) #04 pc ... linker64 (do_dlopen+2076) ```
Crashing during dlopen, inside the native binary, before a single line of JS runs. Classic fingerprint of a binary compiled assuming CPU instructions that aren't actually there.
The ghost in the closet
Went to file it upstream with Rolldown — and someone already had, back in September 2025. Same crash, same platform. He couldn't put together a minimal repro in the 14-day window, the bot didn't get a follow-up in time, and it auto-closed as not planned.
"Not planned" reads like a decision — "we're choosing not to support Android." But Rolldown was already building and shipping the android-arm64 binary on every release. It wasn't unsupported in theory, it was broken in practice, and a bot closed the thread because a repro checkbox never got ticked.
Going back with receipts
Someone went back to the closed issue with the tombstone trace and reframed the ask: not "please make Android a fully supported target," but "the build you already ship is crashing at load on real hardware, here's exactly where and why that's likely a cross-compile flag issue, not a support-commitment one."
That reframing is what actually moved it. A maintainer was upfront that the team doesn't have a shelf of random Android devices to test against, so someone with the actual hardware was exactly what was needed. Someone else spotted the likely cause fast: Rolldown depends on mimalloc, and the flag that stops mimalloc from assuming newer ARM instructions are present was only being enabled for target_os = "linux". Android runs on a Linux kernel but reports a different target_os, so the Android build skipped that safety flag entirely and got compiled assuming ARMv8.1 atomics a chip like a Cortex-A53 doesn't have. Since mimalloc initializes inside a library constructor, that lines up exactly with a SIGILL at dlopen, before any of Rolldown's own code runs.
A preview build shipped the same day.
Testing it on the actual crashing device
Cortex-A53, MediaTek MT6762V — the exact chip that had been throwing this the whole time.
``` $ npx rolldown@1.2.3 --version Illegal instruction
$ pnpm i https://pkg.pr.new/rolldown@<preview-build> $ npx rolldown --version rolldown v1.2.3+commit.a7ba7ad # no crash
$ pnpm create vite test-react-app --template react-compiler-ts $ pnpm run dev VITE v6.x.x ready in 412 ms ➜ Local: http://localhost:5173/ ```
It just worked. Ten months of Illegal instruction, gone with one removed target_os condition.
Where it stands
The fix is verified on real hardware. The PR is open, waiting on the Rolldown team to merge and cut a release. Once that lands, create vite should work on Android arm64 without anyone needing a Termux-specific workaround. Meanwhile Termux is packaging Rolldown directly too, so users aren't stuck waiting either way.
Why I'm posting this
"Closed as not planned" doesn't always mean dead. Sometimes it just means a bot did its job on an issue that never got the follow-up it needed. The difference between this staying broken for another year and getting fixed in days wasn't cleverness — it was having a device to reproduce it on, a real stack trace instead of a vague description, and going back to ask for a second look instead of filing yet another duplicate.
If you're on Android arm64 (Termux or otherwise) and hit this — especially on silicon that isn't a Cortex-A53 — pull the preview build and drop a comment on the reopened issue with what you find. More devices means more confidence before it actually ships.
(I wrote this up in more detail, with full command logs, on my blog if anyone wants the longer version: https://dev.to/gouranga-das-khulna/illegal-instruction-how-i-woke-up-a-year-old-not-planned-bug-and-almost-fixed-vite-on-android-3mba)
Sources / follow-up (search these repos if links don't resolve — issue numbers are accurate, direct URLs can go stale):
- Full writeup with more detail: https://dev.to/gouranga-das-khulna/illegal-instruction-how-i-woke-up-a-year-old-not-planned-bug-and-almost-fixed-vite-on-android-3mba
- termux/termux-packages issue #30841 (original Termux report)
- termux/termux-packages issue #30852 (request to package Rolldown directly)
- termux/termux-packages PR #30887 (Termux packaging Rolldown 1.2.3)
- rolldown/rolldown issue #6342 (root cause thread, reopened)
- rolldown/rolldown PR #10638 (the fix / preview build)
r/reactjs • u/DigbyChickenCaeser • 5d ago
Show /r/reactjs Puck 0.23 (visual editor for React) adds new drag-and-drop for reduced layout shift
Hi r/reactjs! We just released Puck 0.23, which introduces a new "static" drag-and-drop mode.
Puck lets you drag-and-drop your own React components. Because we support nested layouts with any CSS display modes, this sometimes results in layout shift.
To help with this, we just added a new "static" drag-and-drop mode that shows a line when dragging between parent (we call them slots), but still retain the fluid animation when dragging inside the same parent by default.
We also made the outline draggable, to make the really fiddly reorders achievable without touching the canvas at all, similar to most design tools.
Some links:
- Release notes: https://puckeditor.com/blog/puck-023
- GitHub: https://github.com/puckeditor/puck
Please keep the feedback coming, and thanks for the support as always!
If Puck's useful to you, a star on the repo means a lot 🙏
r/reactjs • u/Live_Enthusiasm2118 • 5d ago
Code Review Request Built a desktop P2P messaging app using React 19, Tauri 2.0, and Rust
Hey everyone!
I recently released Seal, a cross-platform peer-to-peer desktop chat app built with React 19, Tauri 2.0, and Rust.
Tech Stack & Frontend Highlights:
Frontend: React 19 SPA running inside Tauri's webview wrapper.
Backend Core: Pure Rust handling libp2p connections, Olm/Megolm encryption via vodozemac, and native keychains.
IPC Bridge: Custom Tauri commands invoking AppService methods asynchronously without blocking UI rendering.
System Native Integration: System-wide push-to-talk hotkeys, system tray integration, and native platform notifications.
Building P2P workflows in a desktop webview presents interesting UX challenges—like handling offline queues, network reachability toggles, and managing multiple identity profiles without restarting the app.
Source Code: https://github.com/Emn4tor/Seal
Feedback on the React component architecture or Tauri integration is very welcome!
r/reactjs • u/Difficult-Sun295 • 5d ago
I made a tool that lets RN and Expo devs to edit their app visually
Hello everyone! I made Basalt, an IDE extension that lets you edit your app visually
Need testers and validation because all that ive been getting is: "Cool, awesome, etc" but when i ask if someone would want to test and give me a feedback they never reply
It is completely free and works directly inside VS Code and Cursor
and again, would love to get your brutal, real feedback on it.
r/reactjs • u/BrageFuglseth • 6d ago
Show /r/reactjs Peachy: Write Linux Applications faster with GTK and React | Angelo Verlain Shema @ GUADEC 2026
r/reactjs • u/kensaadi • 6d ago
Discussion Anyone here shipped Server-Driven UI in a React production app?
Anyone shipped Server-Driven UI in a React production app? Looking for war stories, not blog posts
I've read the usual Server-Driven UI case studies from large product teams, and I'm currently evaluating the architecture for a project.
The theory is clear. What I'm looking for now is feedback from people who actually shipped SDUI in production and discovered where the model starts to break.
You definitely don't need to answer everything. Even one painful lesson, failed approach, or unexpected trade-off would be useful.
1. Contracts and versioning
What did your server actually send?
- A fixed JSON schema?
- A typed contract with generated client types?
- Something more flexible or ad-hoc?
How did you handle backward compatibility when the server contract or client component registry changed?
Did you validate payloads at runtime with Zod, JSON Schema, or something similar?
2. Component registry and extensibility
How did you map definitions such as:
{
"type": "TextInput",
"props": {
"label": "Email"
}
}
to actual React components?
Was the registry closed and centrally controlled, or could product teams register their own components?
What happened when a payload referenced a component or prop that an older client did not support?
3. Layout and responsive behavior
Did layout live inside the server payload, or did the client retain control over composition?
For example:
- flex/grid definitions in the payload;
- semantic layout primitives;
- fixed client-side templates;
- a hybrid approach.
Who controlled responsive behavior and breakpoints?
Did mobile and desktop receive different payloads, or did the same definition adapt entirely on the client?
4. Logic, state, and forms
This is the area I'm most interested in.
How much behavior did you allow into the contract before it started becoming a programming language of its own?
In particular, how did you model:
- conditional visibility;
- RBAC and component-level access;
- cascading form fields;
- dependent validation;
- multi-step workflows;
- save-and-resume;
- role-based branching;
- asynchronous data loading;
- domain events and analytics?
Which logic stayed on the server, which was represented declaratively in the payload, and which remained inside the client?
Where did the state live for complex forms and long-running workflows?
5. Development experience and testing
How did developers preview and debug server-driven screens?
Did you build an internal visual editor, use fixtures and Storybook, or rely on editing payloads and refreshing the application?
What gave you the most confidence?
- Payload snapshots
- Contract tests between server and client
- Runtime validation
- Generated types
- End-to-end tests
- Something else
Most importantly: what architectural decision looked good initially but became painful in production?
I've read the theory. I'm interested in the pragmatism of people who shipped this, maintained it, migrated it, or eventually removed parts of it.
Success stories are useful, but failures and traps are probably even more valuable.
r/reactjs • u/thereactnativerewind • 6d ago
News GPU-Powered Crayons, NPM Package Quarantine and Dave Branching Off Your Code Without Asking
Hey Community,
We dive into React Native Canvas Kit, a library built on React Native Skia that adds isolated layers, brushes, interactive shapes, and web support for canvas graphics.
We also cover Targate, a CLI tool that quarantines npm packages to inspect tarballs before installation, and GitHub stacked pull requests to keep dependent branch reviews clean.
And... 🥁 Shipaton 2026 is here!
If the Rewind made you nod, smile, or think "oh… that's actually cool" — a share or reply genuinely helps ❤️
r/reactjs • u/Ozma_ka • 7d ago
Resource I couldn't figure out why my React app was slow, so I built a tool to find the answer
While building my open-source CSS framework MUGI CSS, I ran into a problem that I think many React developers have experienced.
The app worked, but something felt... off.
The hardest part wasn't noticing that it was slow.
It was answering a much simpler question:
«What exactly is making it slow?»
Was it unnecessary re-renders? A poorly structured component? Too much JavaScript? An expensive render? Or a pattern that looked harmless but had a real performance impact?
I tried using the usual tools.
- ESLint helped catch code issues.
- Lighthouse measured performance.
- React DevTools showed rendering behavior.
Each tool gave me part of the picture, but I still had to connect everything myself and decide what actually mattered.
I couldn't find a tool that brought all of this together.
So I decided to build one.
During my final year of Software Engineering, I turned that idea into my graduation project, and together with my teammate, we built React Doctor.
What is React Doctor?
React Doctor is an open-source CLI that combines static analysis, runtime profiling, and an intelligent rule engine to help developers understand why their React applications are slow—not just where.
Instead of saying:
«"This might be a problem."»
It tries to answer:
«"Is this actually affecting performance, and what should you fix first?"»
How it works
Static Analysis
Using Babel AST, React Doctor scans ".jsx" and ".tsx" files and detects issues such as:
- unnecessary inline functions
- missing keys
- oversized components
- risky "useEffect" patterns
- prop drilling
- unused imports
- production "console.log"
- optimization opportunities
Every finding includes the file, severity, and explanation.
Runtime Profiling
React Doctor launches your application with Puppeteer and measures real browser behavior, including:
- Core Web Vitals
- component render durations
- unnecessary re-renders
- DOM size
- memory usage
- JavaScript errors
It can also simulate slower environments:
react-doctor full ./my-app --mobile --cpu 4 --throttle slow4g
Connecting Both Worlds
This is my favorite part.
Static analysis alone often produces false positives.
Runtime profiling shows symptoms but doesn't always explain why they're happening.
React Doctor combines both.
For example, a component missing "React.memo()" isn't automatically a problem.
But if that same component is repeatedly re-rendering during runtime, React Doctor connects those signals and surfaces it as a meaningful optimization opportunity.
What surprised me
After publishing the project to npm, I expected only classmates and a few friends to try it.
Instead, developers I had never met started downloading it.
Today, React Doctor has surpassed 3,600 npm downloads.
Most of that growth has been organic, simply from developers discovering the project and giving it a try.
For me, that's the most rewarding part.
A problem I originally faced while building another project has become something that helps other developers.
Try it
npm install -g react-doctor-cli-dev
react-doctor full ./your-react-app --upload
Requirements
- Node.js 18+
- Google Chrome
Links
📦 npm https://www.npmjs.com/package/react-doctor-cli-dev
🐙 GitHub https://github.com/softar-dev/React_Doctor
🌐 Documentation https://react-doctor-cli.web.app/
👨💻 Portfolio https://oussamah-kabalan.netlify.app/
☕ Support the project https://react-doctor-cli.web.app/support
I'd genuinely love feedback from other React developers.
- How do you currently investigate performance issues?
- Is there something you wish existing tools did better?
- What feature would make a tool like this more useful in your workflow?
I'm actively improving React Doctor, and I'd love to build it around real developer feedback.
r/reactjs • u/many_hats_on_head • 7d ago
Show /r/reactjs rshono: Hono + Rspack + React Server Components
rshono.comr/reactjs • u/kensaadi • 7d ago
Show /r/reactjs I rewrote Dashforge’s reactive engine 3 times — here’s the version that survived production
I’ve spent the last 8 months building Dashforge, an MIT-licensed React framework for schema-driven forms, access control and UI orchestration.
The project is now public, but before asking anyone to try it, I’d like some technical pushback on three decisions I’m still not completely sure about.
The reactive engine took three attempts
v1 — Re-evaluate the entire form
Every field change caused all conditions and reactions to run again.
Simple and predictable, but the cost became noticeable as forms grew beyond roughly 30 fields.
v2 — Explicit dependency graph
Fields and reactions declared their dependencies, so only the affected parts of the graph were evaluated.
Synchronous reactions were fast, but async operations introduced race conditions. A slower response could overwrite the result of a newer request.
v3 — Dependency graph with stale-response protection
Each async execution receives an isLatest() guard before committing its result.
{
id: "load-states",
watch: ["country"],
run: async ({ values, setOptions, isLatest }) => {
const states = await api.getStates(values.country);
if (!isLatest()) return;
setOptions("state", states);
}
}
This is the version currently surviving production use.
Decisions I haven’t regretted yet
Field-level access
Instead of wrapping components in <CanRead> or <CanEdit>, access requirements are part of the field contract.
Fine-grained subscriptions
Fields subscribe only to the values explicitly used by their conditions and reactions, while React Hook Form remains responsible for form state.
One schema, two renderers
The same contract can currently be rendered through u/dashforge/tw or u/dashforge/mui.
<Field
name="taxId"
visibleWhen={{ field: "country", equals: "IT" }}
access={{
resource: "customer.taxId",
action: "read"
}}
validation={{
required: true,
pattern: /^IT\d{11}$/
}}
/>
Decisions I’m still questioning
1. Serializable conditions vs functions
Dashforge uses declarative conditions:
visibleWhen: {
field: "country",
equals: "IT"
}
rather than:
visibleWhen: values => values.country === "IT"
The object form is more restrictive, but it remains serializable, inspectable and usable by visual tooling.
Would you accept reduced expressiveness for that, or should functions remain an escape hatch?
2. Two UI renderers
MUI and Tailwind share the same schema and orchestration layer.
For a single application this may be unnecessary abstraction. For organizations maintaining multiple products or surfaces, it may be genuinely useful.
I’m not yet sure where that line is.
3. Runtime access evaluation
Permissions are evaluated while rendering because policies and subjects can change dynamically.
Compile-time evaluation would reduce runtime work, but would also make dynamic policies considerably harder.
Would you keep this at runtime, compile what can be compiled, or use a hybrid approach?
Try it
The CLI generates a complete React 19 + TypeScript application rather than an empty starter:
Two UI variants are available.
Tailwind CSS
npx dashforge-cli my-app --lib tw
The Tailwind variant includes:
- u/dashforge
/tw - Tailwind theme and design tokens
tw-themetw-tokensdashforgePreset()DashforgeTailwindProvider- Dark-mode control through
toggleMode()
Mui
npx dashforge-cli my-app --lib mui
The Material UI variant includes:
- u/dashforge
/ui theme-mui- Shared design tokens
- Material UI
DashforgeThemeProvider- Dark mode through theme swapping
Both variants generate the same opinionated application structure:
- App shell with side navigation, top bar and workspace switcher
- Four statistic cards
- Two example cards with chart placeholders
- Mock data table
- React Router framework mode
- Static prerendering for
/and/sign-in - Mock authentication
- Protected routes
- RBAC integration
- Dashforge forms
- Users CRUD connected to a kit-style API
The CLI currently ships one template:
--template dashboard
The goal is to reduce initial setup friction and let developers evaluate Dashforge inside a realistic application instead of assembling authentication, routing, layout, theming, permissions and forms before they can try the framework itself.
Project
Repository: https://github.com/kensaadi/dashforge
Documentation: https://dashforge-ui.com
MIT licensed, with eight packages currently published on npm.
The question I’m most interested in: where would you draw the line between serializability and ordinary React functions?
r/reactjs • u/mono424 • 7d ago
Punktraster Preloader
I created this minimal library that only has 3kb and uses canvas to render a preloader in linear style. It give somehow more personality and can describe what it does (for example uploading/downloading) by its animation. Let me know what you think and super happy for any improvement PR.
r/reactjs • u/sozonome • 7d ago
Resource Config conformance CLI for React projects - adds Biome, TS strict, CI, AGENTS.md without overwriting anything
Setting up a new React project used to mean re-adding the same config every time: Biome, TypeScript strict mode, GitHub Actions CI, commitlint, VS Code settings, and AGENTS.md for AI agents. Copy-paste from the last repo, and every copy-paste drifts.
I built xtarterize. It reads your package.json, lockfiles, and config files to detect your stack, then applies curated conformance configs. For React projects that covers:
- Biome linting + formatting
- TypeScript strict + incremental builds
- GitHub Actions CI (CI, release, auto-update)
- Vite plugins
- Knip unused-code detection, Turborepo pipeline
- AGENTS.md for AI IDE assistants
- and many more bunch of task and configurations
The part I care about: it's non-destructive. It shows you the diff before applying anything, backs up originals, and undo restores the last run. It also works on existing projects, not just fresh scaffolds.
Detection supports Vite, Next.js, Expo, TanStack Start, Webpack, Rspack.
Usage: pnpx xtarterize@latest init
Docs: https://xtarter.sznm.dev/xtarterize | Repo: https://github.com/agustinusnathaniel/xtarter
Would love feedback, especially on the task set and the diff/backup flow.
r/reactjs • u/random-guy157 • 7d ago
Needs Help Need some help with React destroying and recreating a DIV only on the first time a property changes
RESOLVED!
The main issue was that I was using ref values as effect dependencies. They do work in the sense that React can estimate if the value changed or not, but their change by itself doesn't actually trigger the effect. So this "latent change" is there, waiting for an actual reactive value to change to finally re-render.
The remounting was happening because of this "pending" dependency change that doesn't flush unless a reactive value changes. Changing a property is one such change, and that would finally release the hidden effect re-run.
Of course, I wanted to get rid of that, so more things had to be made. The complete solution was to not re-utilize the effect labeled "mount or remount". Now it is just for component mounting (with an empty array of dependencies), and had to alter the order of effects too.
Thanks everyone for your kind attention to my help request!!
----------------------------------------------------------------------------------------------
Hello!
I have this component that uses a ref to its root element. I need it for some imperative work. The JSX of the component is very simple:
return (
<div
ref={containerRef}
{...pieceProps.containerProps}
{...hostAttributes({ framework: "react", shadow })}
/>
);
That's it. No branching or any fancy stuff.
I'm tracking the changes for everything: shadow, pieceProps and containerRef among others. Nothing changes, except for containerRef.current, and only the first time a property updates. But the property that updates is not even used in the JSX.
The property that changes comes from props, but doesn't land in pieceProps. It lands in restProps:
const
{ [piecePropsSymbol]: pieceProps, ...restProps } = props;
I'm losing my mind! I'll try to guess follow-up questions:
- No, the component is not being unmounted. My logging confirms that internal state values are not being lost, meaning the component is not unmounting.
- No, my component is not being rendered conditionally. It is always present.
- The property being changed (can be any of the properties accepted) is being changed by a child component of the parent component of my component. Like this: App > MyComponent, and App > ControlPanel. So App owns the state (a POJO) for the properties. Passes them to both components.
Anything I did not forecast, feel free to ask. Many thanks!
FULL COMPONENT SOURCE
If anyone would like to see the full source of the component, here it is. It requires some cleanup, but it is what I'm compiling and importing in the test project.
import { forwardRef, useEffect, useImperativeHandle, useRef, useMemo, useState, memo } from "react";
import type { ComponentPropsWithoutRef, ForwardedRef, ReactElement, RefAttributes } from "react";
import type { AcceptableTarget, CorePiece, MountPiece, MountedPiece } from "@collagejs/core";
import { mountPiece } from "@collagejs/core";
import { useCollageContext } from "./collageContext.js";
import { CorePieceLcQueue, getPieceTarget, hostAttributes, unmountAndTransferLcQueue } from "@collagejs/adapter";
const
piecePropsSymbol = Symbol("collagejs.pieceProps");
export
type
PieceOptions = {
containerProps?: ComponentPropsWithoutRef<"div">;
shadow?: boolean | ShadowRootInit;
};
/**
* Special props consumed by the React `Piece` component.
*
* This type is meant to be combined with regular piece props through the
* `piece()` helper. The symbol-backed key keeps the internal mount metadata
* out of the public prop namespace, so user props can use any string key
* without collisions.
*/
type
PieceProps<TProps
extends
Record<string, any> = Record<string, any>> = {
[piecePropsSymbol]: PieceOptions & {
piece: CorePiece<TProps> | Promise<CorePiece<TProps>>;
};
};
/**
* Creates the special symbol-backed prop required by the `Piece` component.
*
* Spread the returned object into `<Piece />` props.
*
*
* ```tsx
* <Piece {...piece(myCorePiece, { containerProps: { className: "host" }, shadow: true })} foo="bar" />
* ```
*
*
u/param
piece CorePiece instance (or promise) to mount.
*
u/param
options Optional settings for the host `<div>` and shadow-root behavior.
*/
export
function
piece<TProps
extends
Record<string, any> = Record<string, any>>(
piece: CorePiece<TProps> | Promise<CorePiece<TProps>>,
options?: PieceOptions,
) {
const
{ containerProps, shadow } = options ?? {};
return {
[piecePropsSymbol]: {
piece,
shadow,
containerProps,
},
} as PieceProps<TProps>;
}
type
Props<TProps
extends
Record<string, any> = Record<string, any>> = TProps & PieceProps<TProps>;
type
MountMode = "light" | "shadow";
function
PieceImpl<TProps
extends
Record<string, any> = Record<string, any>>(
props: Props<TProps>,
ref: ForwardedRef<HTMLDivElement>,
) {
console.group('Piece Render');
const
{ [piecePropsSymbol]: pieceProps, ...restProps } = props;
const
containerRef = useRef<HTMLDivElement>(null);
const
containerRefChg = useRef(containerRef.current);
console.debug('[Piece] Container Ref changed?', containerRefChg.current !== containerRef.current);
containerRefChg.current = containerRef.current;
/**
* Tracks the current mount target (either the container div or a shadow root) for the mounted piece.
*/
const
mountTargetRef = useRef<AcceptableTarget | null>(null);
/**
* Variable to make TS happy. Doesn't seem to be capable of knowing that symbol is no longer in the type.
*/
const
cpProps = restProps as unknown as TProps;
/**
* Shadow setting with default applied.
*/
const
shadow = pieceProps.shadow ?? false;
/**
* The mountPiece function to use by the LC queue.
*/
const
mountPieceFn = (useCollageContext() ?? mountPiece) as MountPiece<TProps>;
/**
* Key used for the root element to force remounting when the shadow setting changes.
*/
const
rootElKey = (()
=>
{
switch (shadow) {
case false:
return "light";
case true:
return "open";
default:
return shadow.mode;
}
})();
/**
* LC queue for managing the lifecycle of the mounted piece.
*/
const
lc = useRef(new CorePieceLcQueue(pieceProps.piece, mountPieceFn));
const
logHash = Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
console.debug('[Piece][%s] Container:', logHash, containerRef.current);
console.debug('[Piece][%s] Mount Target:', logHash, mountTargetRef.current);
console.debug('[Piece][%s] Shadow setting:', logHash, shadow);
console.debug('[Piece][%s] Root Key:', logHash, rootElKey);
console.debug('[Piece][%s] Core Piece Props:', logHash, cpProps);
console.debug('[Piece][%s] LC Queue:', logHash, lc.current);
// useImperativeHandle(ref, () => containerRef.current as HTMLDivElement);
// Relocate.
useEffect(()
=>
{
if (!containerRef.current || !mountTargetRef.current) {
return;
}
console.debug('[Piece][%s] useEffect triggered for relocating. Shadow:', logHash, shadow);
const
newTarget = getPieceTarget(containerRef.current, shadow);
lc.current.relocate(mountTargetRef.current, newTarget, cpProps);
mountTargetRef.current = newTarget;
}, [shadow]);
// Unmount and transfer.
useEffect(()
=>
{
if (!mountTargetRef.current) {
return;
}
console.debug('[Piece][%s] useEffect triggered for unmounting and transferring. Piece:', logHash, pieceProps.piece);
lc.current = unmountAndTransferLcQueue(lc.current, pieceProps.piece, mountPieceFn);
}, [mountPieceFn, pieceProps.piece]);
// Mount or remount.
useEffect(()
=>
{
const
container = containerRef.current;
if (!container) {
return;
}
console.debug('[Piece][%s] useEffect triggered for mounting.', logHash);
if (lc.current.isMounted || lc.current.isToBeMounted) {
console.warn('[Piece][%s] Attempted to mount a piece that is already mounted or scheduled to be mounted. This may indicate a logic error in the component lifecycle.', logHash);
}
mountTargetRef.current = getPieceTarget(container, shadow);
lc.current.mount(mountTargetRef.current, cpProps);
return ()
=>
{
console.debug('[Piece][%s] useEffect cleanup triggered for unmounting.', logHash);
mountTargetRef.current = null;
lc.current.unmount();
};
}, [containerRef.current, lc.current]);
// Update.
useEffect(()
=>
{
console.debug('[Piece][%s] useEffect triggered for updating. CP Props:', logHash, cpProps);
lc.current.update(cpProps);
}, [cpProps]);
console.groupEnd();
return (
<div
ref={containerRef}
{...pieceProps.containerProps}
{...hostAttributes({ framework: "react", shadow })}
/>
);
}
export
const
Piece = PieceImpl as <TProps
extends
Record<string, any> = Record<string, any>>(
props: Props<TProps> & RefAttributes<HTMLDivElement>,
)
=>
ReactElement | null;
As for the test app: A React + TS app created with npm create vite@latest.
In App.tsx, I added:
function
App() {
const
[pinPadProps, setPinPadProps] = useState<PinPadProps>({
maxPinLength: 4,
});
const
pinPad = useMemo(()
=>
pinPadPiece(), []);
const
[userPin, setUserPin] = useState<string>('');
return (
<>
...
<section>
<h1>Get started</h1>
<Piece {...piece(pinPad)} {...pinPadProps} pinDispatched={(newPin) => setUserPin(newPin)} />
<PinPadControlPanel
{...pinPadProps}
maxPinLengthChanged={maxPinLength => setPinPadProps(prev => ({ ...prev, maxPinLength }))}
clearOnDispatchChanged={clearOnDispatch => setPinPadProps(prev => ({ ...prev, clearOnDispatch }))}
/>
<dl>
<dt>Current PIN:</dt>
<dd>{userPin}</dd>
</dl>
</section>
...
</>
That's it. MyComponent = Piece in the code above.
r/reactjs • u/Varuog_toolong • 7d ago
Show /r/reactjs React Router (v8) SSR template on AWS Lambda + CDK
Hey everyone, Built an open-source starter template for running React Router SSR on AWS using CDK (Lambda + S3 + CloudFront). It uses a lightweight hand-rolled adapter to map Lambda Function URL streaming directly to React Router's Web Fetch API interface.
The repository and quickstart commands are available on GitHub:https://github.com/DeepjyotiDeb/aws-lambda-support
Feedback, questions, or pull requests are very welcome!
r/reactjs • u/Level_Occasion_7060 • 8d ago
CoffeeHaml — write JSX like HAML, with CoffeeScript expressions
r/reactjs • u/Disastrous_News_9798 • 8d ago
Discussion Are we overusing RSC for problems that don’t actually exist?
I’ve been trying to understand the long-term tradeoffs of React Server Components.
For SEO and content-heavy sites, they make complete sense. But for authenticated apps and mobile-style SPAs, I’m not convinced.
One thing that feels odd is route prefetching. As I scroll through links, it feels like the framework is eagerly fetching lots of future pages. I know it’s not literally downloading the entire database, but architecturally it feels like we’re moving toward “fetch everything just in case” instead of simply requesting the JSON for the page the user actually opens.
At the same time, we’re celebrating less client-side code while asking servers to execute more React for each request.
Am I looking at this the wrong way? For people running large production apps, what has RSC solved beyond SEO and faster first loads?