Skip to content

Commit 2795294

Browse files
committed
Testing clojure-mcp with mcphub
1 parent b14aa40 commit 2795294

2 files changed

Lines changed: 236 additions & 0 deletions

File tree

.mcphub/servers.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"mcpServers": {
3+
"clojure-mcp": {
4+
"args": ["-c", "clojure -X:user/mcp :port $(cat .shadow-cljs/nrepl.port)"],
5+
"command": "/bin/bash"
6+
},
7+
"language-server": {
8+
"command": "/bin/bash",
9+
"args": ["-c", "mcp-language-server --workspace ${CWD} --lsp clojure-lsp listen"]
10+
}
11+
}
12+
}

PROJECT_SUMMARY.md

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
# PROJECT SUMMARY: Reagent
2+
3+
## Overview
4+
Reagent is a minimalistic ClojureScript interface to React that provides a functional, reactive programming model for building web user interfaces. It uses Hiccup-style syntax (vectors) to represent React components and provides reactive atoms (ratoms) for state management with automatic re-rendering.
5+
6+
## Key Features
7+
- **Hiccup-style templating**: Write HTML using Clojure vectors `[:div "Hello"]`
8+
- **Reactive programming**: Built-in reactivity using ratoms that automatically trigger re-renders
9+
- **React interoperability**: Easy integration with existing React components
10+
- **Minimal overhead**: Thin wrapper around React with small footprint
11+
- **Functional approach**: Immutable data structures and functional components
12+
13+
## Project Structure
14+
15+
### Core Source Files (`src/reagent/`)
16+
- **`core.cljs`**: Main public API with 30+ functions including `atom`, `create-element`, `as-element`, `track`, `cursor`, `wrap`, `class-names`, `merge-props`, and React interop utilities
17+
- **`core.clj`**: Macro definitions for ClojureScript compilation
18+
- **`ratom.cljs`**: Reactive atom implementation with dependency tracking and batched updates
19+
- **`dom.cljs`**: DOM rendering functions, React DOM integration
20+
- **`debug.cljs`**: Development debugging utilities with assertion macros
21+
22+
### Implementation Details (`src/reagent/impl/`)
23+
- **`template.cljs`**: Hiccup vector to React element conversion logic
24+
- **`component.cljs`**: React component lifecycle and state management
25+
- **`batching.cljs`**: Update batching system for performance optimization
26+
- **`util.cljs`**: Utility functions for props merging and component helpers
27+
- **`input.cljs`**: Input component handling for controlled components
28+
- **`protocols.cljs`**: Core protocols for reactive atoms and components
29+
30+
### Configuration & Dependencies
31+
- **`project.clj`**: Leiningen build configuration with ClojureScript setup
32+
- **`deps.edn`**: tools.deps configuration for modern Clojure CLI workflows
33+
- **`shadow-cljs.edn`**: Shadow CLJS build configuration with browser, test, and prerender targets
34+
- **`bb.edn`**: Babashka task configuration for development workflows
35+
- **`examples/`**: Sample applications demonstrating different Reagent patterns
36+
37+
## Key Dependencies
38+
- **ClojureScript 1.11.132**: Core language platform
39+
- **React 18.2.0-1**: Underlying React framework via cljsjs
40+
- **React DOM 18.2.0-1**: DOM rendering support via cljsjs
41+
42+
## Core APIs and Usage Patterns
43+
44+
### Basic Component Creation
45+
```clojure
46+
(ns my-app.core
47+
(:require [reagent.core :as r]
48+
[reagent.dom :as rdom]))
49+
50+
;; Simple component
51+
(defn hello-world []
52+
[:div "Hello, world!"])
53+
54+
;; Component with parameters
55+
(defn greeting [name]
56+
[:h1 "Hello, " name "!"])
57+
```
58+
59+
### Reactive State Management
60+
```clojure
61+
;; Create reactive atom
62+
(def app-state (r/atom {:counter 0}))
63+
64+
;; Component using reactive state
65+
(defn counter []
66+
[:div
67+
[:p "Count: " (:counter @app-state)]
68+
[:button {:on-click #(swap! app-state update :counter inc)} "+"]])
69+
```
70+
71+
### Advanced Reactive Features
72+
```clojure
73+
;; Computed values that update automatically
74+
(def doubled-counter (r/track #(* 2 (:counter @app-state))))
75+
76+
;; Eager tracking (starts immediately)
77+
(def eager-tracker (r/track! #(println "Counter changed:" (:counter @app-state))))
78+
79+
;; Cursor for nested state access
80+
(def counter-cursor (r/cursor app-state [:counter]))
81+
82+
;; Wrap values with custom reset behavior
83+
(def wrapped-value (r/wrap (:counter @app-state)
84+
swap! app-state assoc :counter))
85+
86+
;; Component lifecycle with ratoms
87+
(defn with-local-state []
88+
(r/with-let [local-state (r/atom 0)]
89+
[:div
90+
[:p "Local: " @local-state]
91+
[:button {:on-click #(swap! local-state inc)} "Increment"]]))
92+
93+
;; Recursive swap for complex state updates
94+
(r/rswap! app-state update :counter inc)
95+
```
96+
97+
### React Interoperability
98+
```clojure
99+
;; Use React components in Reagent
100+
(def react-component (r/adapt-react-class js/SomeReactComponent))
101+
102+
;; Use Reagent components in React
103+
(def reagent-for-react (r/reactify-component my-reagent-component))
104+
105+
;; Create React elements directly
106+
(r/create-element "div" #js{:className "foo"} "Hello")
107+
108+
;; Create React classes with full lifecycle control
109+
(def my-class
110+
(r/create-class
111+
{:component-did-mount (fn [this] (println "Mounted!"))
112+
:reagent-render (fn [] [:div "Custom class component"])}))
113+
114+
;; Utility functions for props and styling
115+
(r/class-names "btn" "btn-primary" {:active true})
116+
(r/merge-props {:class "base"} {:class "extra" :id "test"})
117+
118+
;; Safe HTML rendering
119+
(r/unsafe-html "<strong>Bold text</strong>")
120+
```
121+
122+
## Architecture Overview
123+
124+
### Reactive System
125+
1. **RAtom**: Core reactive atom type that tracks dependencies
126+
2. **Track**: Computed values that automatically update when dependencies change
127+
3. **Batching**: Updates are batched and applied after render for performance
128+
4. **Dependency Graph**: Automatic tracking of which components depend on which atoms
129+
130+
### Component Rendering
131+
1. **Template Compilation**: Hiccup vectors converted to React elements
132+
2. **Component Wrapping**: Reagent functions wrapped as React components
133+
3. **State Integration**: React state integrated with Reagent ratoms
134+
4. **Lifecycle Management**: React lifecycle methods available when needed
135+
136+
### Update Flow
137+
```
138+
Atom Change → Dependency Tracking → Batched Update → Component Re-render
139+
```
140+
141+
## Development Workflow
142+
143+
### Setting Up Development
144+
```bash
145+
# Using Shadow CLJS (modern approach)
146+
npx shadow-cljs watch client
147+
148+
# Using Babashka tasks
149+
bb shadow # Start Shadow CLJS watch mode
150+
bb build-report # Generate build analysis report
151+
152+
# Running tests
153+
lein doo chrome-headless test auto
154+
npx shadow-cljs compile test # Shadow CLJS test compilation
155+
```
156+
157+
### REPL-Driven Development
158+
- Start REPL with `lein repl` or `clj -M:dev`
159+
- Connect to ClojureScript REPL for live coding
160+
- Hot-reloading with Figwheel automatically updates components when code changes
161+
- Reactive atoms automatically trigger re-renders when state changes
162+
163+
### Building for Production
164+
```bash
165+
lein build # Creates optimized build
166+
lein build-examples # Builds example applications
167+
```
168+
169+
## Implementation Patterns
170+
171+
### Component Design Patterns
172+
1. **Pure Functions**: Components as pure functions of props and state
173+
2. **Reactive State**: Use ratoms for local and global state
174+
3. **Props Destructuring**: `(defn my-comp [{:keys [title content]}] ...)`
175+
4. **Conditional Rendering**: Use `when`, `if`, and `case` directly in hiccup
176+
177+
### State Management Patterns
178+
1. **Global App State**: Single ratom with nested maps
179+
2. **Cursors**: For accessing nested state without re-rendering parent
180+
3. **Computed Values**: Use `track` for derived state
181+
4. **Local Component State**: Use `r/with-let` for component-local atoms
182+
183+
### Performance Optimization
184+
1. **Batched Updates**: Updates automatically batched by Reagent with `flush` and `after-render` control
185+
2. **Minimal Re-renders**: Only components using changed atoms re-render
186+
3. **React Keys**: Use `:key` metadata for list items
187+
4. **shouldComponentUpdate**: Use `React.memo` equivalent with `r/create-class`
188+
5. **Manual Rendering Control**: Use `r/flush` to force immediate renders, `r/next-tick` and `r/after-render` for timing control
189+
6. **Compiler Customization**: Create custom compilers with `r/create-compiler` for specialized rendering behavior
190+
191+
## Extension Points
192+
193+
### Custom Components
194+
- Extend with React lifecycle methods using `r/create-class`
195+
- Create reusable component libraries
196+
- Build higher-order components
197+
198+
### State Management Extensions
199+
- Custom ratom-like types implementing `IReactiveAtom`
200+
- Middleware for state changes and debugging
201+
- Integration with external state management (Redux, etc.)
202+
203+
### React Ecosystem Integration
204+
- Wrap third-party React components with `r/adapt-react-class`
205+
- Export Reagent components for React with `r/reactify-component`
206+
- Use React hooks through interop
207+
208+
### Development Tools
209+
- Custom debugging and inspection tools
210+
- Development-only components and utilities
211+
- Performance monitoring and profiling extensions
212+
213+
## Testing Strategy
214+
- Unit tests in `test/` directory using ClojureScript test framework
215+
- Component testing with simulated user interactions
216+
- Integration tests with full application state
217+
- Use `doo` for automated browser testing
218+
219+
## Common Gotchas
220+
1. **Deref in Render**: Always deref atoms (`@atom`) in component render functions
221+
2. **Event Handlers**: Use anonymous functions `#(...)` or `partial` for event handlers
222+
3. **Keys for Lists**: Always provide `:key` metadata for dynamic lists
223+
4. **State Updates**: Use `swap!` or `reset!`, never mutate ratom contents directly
224+
5. **Component Names**: Use kebab-case for component function names

0 commit comments

Comments
 (0)