Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion AGENTS.MD
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Chrome DevTools Protocol (CDP)을 활용하여 원격 크롬 브라우저를 제
- **@ohah/chrome-remote-devtools-client**: CDP 클라이언트 (JavaScript, 웹페이지에 로드)
- **@ohah/chrome-remote-devtools-inspector**: Inspector UI (React + Vite, 웹/데스크탑 공유)
- **@ohah/chrome-remote-devtools-inspector-react-native**: React Native Inspector 플러그인 (JavaScript 레이어 콘솔·네트워크 훅, MMKV/Redux 등)
- **@ohah/chrome-remote-devtools-react-native-devtools**: React Native DevTools 데스크탑 앱 (Electrobun + React + Vite)

### 통신 흐름
1. 클라이언트(`client`)가 WebSocket으로 서버에 연결
Expand All @@ -89,7 +90,8 @@ chrome-remote-devtools/
│ └── server/ # WebSocket 중계 서버 (Rust)
├── packages/
│ ├── client/ # CDP 클라이언트 (웹페이지용)
│ └── inspector/ # Inspector UI (React + Vite, 웹/데스크탑)
│ ├── inspector/ # Inspector UI (React + Vite, 웹/데스크탑)
│ └── react-native-devtools/ # React Native DevTools 데스크탑 앱 (Electrobun)
├── document/ # RSPress 문서 페이지
│ ├── docs/ # 문서 소스
│ └── rspress.config.ts
Expand Down Expand Up @@ -128,6 +130,9 @@ cargo run --bin chrome-remote-devtools-server # Rust 서버만
bun run dev:inspector # Inspector 웹만
bun run dev:inspector:tauri # Inspector 데스크탑
bun run dev:docs # 문서 페이지 (document 패키지)
bun run dev:react-native-devtools # React Native DevTools 데스크탑 앱
bun run dev:react-native-devtools:hmr # React Native DevTools (HMR)
# bun run dev 시 React Native DevTools 앱도 기본으로 함께 실행 (끄려면 INCLUDE_REACT_NATIVE_DEVTOOLS=false)

# 코드 품질
bun run lint # oxlint
Expand All @@ -137,6 +142,7 @@ bun run format:rust # rustfmt
# 빌드
bun run build # 전체 빌드
bun run build:docs # 문서 빌드 (document 패키지)
bun run build:react-native-devtools # React Native DevTools 데스크탑 앱
```

### 이 레포 PR·push (ohah 전용)
Expand Down Expand Up @@ -275,6 +281,7 @@ function 연결상태업데이트() {
- 콘솔 훅(JS): `src/console/`
- 네트워크 훅(JS): `src/network/`
- MMKV/AsyncStorage/Redux: `src/mmkv/`, `src/async-storage/`, `src/redux-devtools-extension.ts`
- React Native DevTools: `packages/react-native-devtools/src/`
- DevTools: `devtools/devtools-frontend/front_end/`
- 문서: `document/docs/`

Expand Down
306 changes: 288 additions & 18 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@react-navigation/native": "^7.1.26",
"@react-navigation/stack": "^7.6.13",
"@reduxjs/toolkit": "^2.11.2",
"react": "19.2.0",
"react": "^19.2.3",
"react-native": "0.83.1",
"react-native-device-info": "15.0.1",
"react-native-gesture-handler": "^2.30.0",
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
"dev:inspector": "bun run --filter='@ohah/chrome-remote-devtools-inspector' dev",
"dev:inspector:tauri": "bun run --filter='@ohah/chrome-remote-devtools-inspector' tauri dev",
"dev:docs": "bun run --filter='docs' dev",
"dev:react-native-devtools": "bun run --filter='@ohah/chrome-remote-devtools-react-native-devtools' dev",
"dev:react-native-devtools:hmr": "bun run --filter='@ohah/chrome-remote-devtools-react-native-devtools' dev:hmr",
"build:react-native-devtools": "bun run --filter='@ohah/chrome-remote-devtools-react-native-devtools' build",
"lint": "oxlint .",
"format": "oxfmt .",
"format:check": "oxfmt . --check",
Expand All @@ -26,7 +29,7 @@
"build:devtools:clean": "rm -rf devtools/devtools-frontend/out && bun run build:devtools",
"build:client": "bun run --filter='@ohah/chrome-remote-devtools-client' build",
"build:docs": "bun run --filter='docs' build",
"postinstall": "playwright install --with-deps chromium",
"postinstall": "playwright install --with-deps chromium && bun scripts/patch-debugger-frontend-sourcemaps.ts",
"test:unit": "bun test packages/server && bun test packages/client && bun test packages/inspector/src && bun test packages/react-native-inspector/src/__tests__",
"test:unit:server": "bun test packages/server --coverage",
"test:unit:client": "bun test packages/client --coverage",
Expand Down
92 changes: 92 additions & 0 deletions packages/react-native-devtools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# React + Tailwind + Vite Electrobun Template

A fast Electrobun desktop app template with React, Tailwind CSS, and Vite for hot module replacement (HMR).

## Getting Started

```bash
# Install dependencies
bun install

# Development without HMR (uses bundled assets)
bun run dev

# Development with HMR (recommended)
bun run dev:hmr

# Build for production
bun run build

# Build for production release
bun run build:prod
```

## How HMR Works

When you run `bun run dev:hmr`:

1. **Vite dev server** starts on `http://localhost:2420` with HMR enabled
2. **Electrobun** starts and detects the running Vite server
3. The app loads from the Vite dev server instead of bundled assets
4. Changes to React components update instantly without full page reload

When you run `bun run dev` (without HMR):

1. Electrobun starts and loads from `views://mainview/index.html`
2. You need to rebuild (`bun run build`) to see changes

## Project Structure

```
├── src/
│ ├── bun/
│ │ └── index.ts # Main process (Electrobun/Bun)
│ └── mainview/
│ ├── App.tsx # React app component
│ ├── main.tsx # React entry point
│ ├── index.html # HTML template
│ └── index.css # Tailwind CSS
├── electrobun.config.ts # Electrobun configuration
├── vite.config.ts # Vite configuration
├── tailwind.config.js # Tailwind configuration
└── package.json
```

## Distribution build (macOS code signing)

To build a signed .app for distribution:

- **다른 사람 Mac에서 경고 없이 실행**하려면 **노타라이즈(notarize)**까지 해야 합니다. 코드 서명만 있으면 받는 쪽에서 "식별되지 않은 개발자" 경고가 뜹니다.
- **본인 기기·테스트만** 쓰면 코드 서명만으로 충분합니다.

1. In `electrobun.config.ts`, under `build.mac`, set `codesign: true`. For distribution to other users, also set `notarize: true`.
2. Environment variables:
- **Codesign**: `ELECTROBUN_DEVELOPER_ID` (e.g. `"Developer ID Application: Your Name (TEAM_ID)"`).
- **Notarize** (필요 시): `ELECTROBUN_APPLEID`, `ELECTROBUN_APPLEIDPASS` (앱 전용 암호), `ELECTROBUN_TEAMID`.

Example (codesign only, 본인 기기/테스트용):

```bash
export ELECTROBUN_DEVELOPER_ID="Developer ID Application: Your Name (XXXXXXXX)"
bun run build
```

Example (codesign + notarize, 다른 기기에서 실행할 때 권장):

```bash
export ELECTROBUN_DEVELOPER_ID="Developer ID Application: Your Name (XXXXXXXX)"
export ELECTROBUN_APPLEID="your@apple.id"
export ELECTROBUN_APPLEIDPASS="app-specific-password"
export ELECTROBUN_TEAMID="XXXXXXXX"
bun run build
```

The built .app will be in the Electrobun output directory (e.g. `dist/` or as per electrobun CLI).

## Customizing

- **React components**: Edit files in `src/mainview/`
- **Tailwind theme**: Edit `tailwind.config.js`
- **Vite settings**: Edit `vite.config.ts`
- **Window settings**: Edit `src/bun/index.ts`
- **App metadata**: Edit `electrobun.config.ts`
30 changes: 30 additions & 0 deletions packages/react-native-devtools/electrobun.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { ElectrobunConfig } from 'electrobun';

export default {
app: {
name: 'react-native-devtools',
identifier: 'dev.electrobun.react-native-devtools',
version: '0.0.1',
},
build: {
// Vite builds to dist/, we copy from there
copy: {
'dist/index.html': 'views/mainview/index.html',
'dist/assets': 'views/mainview/assets',
},
mac: {
bundleCEF: true,
defaultRenderer: 'cef',
// Code signing: codesign needs ELECTROBUN_DEVELOPER_ID only.
// codesign: true, // env: ELECTROBUN_DEVELOPER_ID
// notarize: true, // env: ELECTROBUN_APPLEID, ELECTROBUN_APPLEIDPASS, ELECTROBUN_TEAMID (only when notarize)
},
linux: {
bundleCEF: true,
defaultRenderer: 'cef',
},
win: {
bundleCEF: false,
},
},
} satisfies ElectrobunConfig;
24 changes: 24 additions & 0 deletions packages/react-native-devtools/llms.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Electrobun Project

This is an Electrobun desktop application.

IMPORTANT: Electrobun is NOT Electron. Do not use Electron APIs or patterns.

## Documentation

Full API reference: https://blackboard.sh/electrobun/llms.txt
Getting started: https://blackboard.sh/electrobun/docs/

## Quick Reference

Import patterns:
- Main process (Bun): `import { BrowserWindow } from "electrobun/bun"`
- Browser context: `import { Electroview } from "electrobun/view"`

Use `views://` URLs to load bundled assets (e.g., `url: "views://mainview/index.html"`).
Views must be configured in `electrobun.config.ts` to be built and copied into the bundle.

## About

Electrobun is built by Blackboard (https://blackboard.sh), an innovation lab building
tools and funding teams that define the next generation of technology.
43 changes: 43 additions & 0 deletions packages/react-native-devtools/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "@ohah/chrome-remote-devtools-react-native-devtools",
"version": "0.1.0",
"private": true,
"description": "React Native DevTools desktop app (Electrobun + React + Vite)",
"repository": {
"type": "git",
"url": "https://github.com/ohah/chrome-remote-devtools.git",
"directory": "packages/react-native-devtools"
},
"scripts": {
"dev": "bun run build && electrobun dev",
"dev:hmr": "concurrently \"bun run hmr\" \"bun run dev\"",
"hmr": "vite --port 2420",
"build": "vite build && electrobun build",
"build:prod": "vite build && electrobun build --channel prod",
"start": "bun run dev"
},
"dependencies": {
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-tooltip": "^1.2.8",
"@tanstack/react-query": "^5.90.12",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"electrobun": "1.12.3",
"lucide-react": "^0.562.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"tailwind-merge": "^3.4.0",
"zustand": "5.0.9"
},
"devDependencies": {
"@tailwindcss/vite": "^4.1.18",
"@types/bun": "latest",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^4.6.0",
"concurrently": "^9.1.0",
"tailwindcss": "^4.1.18",
"typescript": "^5.7.2",
"vite": "^6.0.3"
}
}
75 changes: 75 additions & 0 deletions packages/react-native-devtools/src/bun/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { BrowserWindow, BrowserView, Updater, Utils } from 'electrobun/bun';

const DEV_SERVER_PORT = 2420;
const DEV_SERVER_URL = `http://localhost:${DEV_SERVER_PORT}`;

// Ref for window control RPC (set after mainWindow is created) / 창 제어 RPC용
let mainWindowRef: BrowserWindow | null = null;

// RPC: fetch URL from main process + window control / CORS 회피용 fetch + 창 제어
const rpc = BrowserView.defineRPC({
handlers: {
requests: {
fetchUrl: async (params?: unknown) => {
const { url } = params as { url: string };
const res = await fetch(url);
if (!res.ok) throw new Error(`Fetch failed: ${res.status}`);
return res.json();
},
closeWindow: async () => {
mainWindowRef?.close();
},
minimizeWindow: async () => {
if (!mainWindowRef) return;
if (mainWindowRef.isMaximized()) mainWindowRef.unmaximize();
mainWindowRef.minimize();
},
// Maximize only; restore disabled to avoid CEF freeze on unmaximize/setFrame
toggleMaximizeWindow: async () => {
if (!mainWindowRef || mainWindowRef.isMaximized()) return;
mainWindowRef.maximize();
},
},
},
});

// Check if Vite dev server is running for HMR
async function getMainViewUrl(): Promise<string> {
const channel = await Updater.localInfo.channel();
if (channel === 'dev') {
try {
await fetch(DEV_SERVER_URL, { method: 'HEAD' });
console.log(`HMR enabled: Using Vite dev server at ${DEV_SERVER_URL}`);
return DEV_SERVER_URL;
} catch {
console.log("Vite dev server not running. Run 'bun run dev:hmr' for HMR support.");
}
}
return 'views://mainview/index.html';
}

// Create the main application window
const url = await getMainViewUrl();

const mainWindow = new BrowserWindow({
title: 'React Native DevTools',
url,
titleBarStyle: 'hidden',
rpc,
styleMask: { Resizable: true, Miniaturizable: true, Closable: true },
frame: {
width: 1024,
height: 768,
x: 200,
y: 200,
},
});

mainWindowRef = mainWindow;

// Quit the app when the main window is closed
mainWindow.on('close', () => {
Utils.quit();
});

console.log('React Tailwind Vite app started!');
33 changes: 33 additions & 0 deletions packages/react-native-devtools/src/mainview/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { TooltipProvider } from '@radix-ui/react-tooltip';
import { useSettingsStore } from '@/shared/lib/settings-store';
import { SettingsModal } from '@/features/settings/ui/settings-modal';
import { TitleBar } from '@/widgets/title-bar/TitleBar';
import { MetroDebuggerPage } from '@/features/metro-debugger/ui/MetroDebuggerPage';

const queryClient = new QueryClient();

function AppContent() {
const isSettingsOpen = useSettingsStore((s) => s.isSettingsOpen);
const closeSettings = useSettingsStore((s) => s.closeSettings);

return (
<div className="h-screen flex flex-col bg-gray-900">
<TitleBar />
<div className="flex-1 overflow-hidden pt-[35px]">
<MetroDebuggerPage />
</div>
<SettingsModal isOpen={isSettingsOpen} onClose={closeSettings} />
</div>
);
}

export default function App() {
return (
<QueryClientProvider client={queryClient}>
<TooltipProvider delayDuration={300}>
<AppContent />
</TooltipProvider>
</QueryClientProvider>
);
}
Loading
Loading