@barefootjs/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/docs/core/README.md +84 -0
  2. package/dist/docs/core/adapters/adapter-architecture.md +262 -0
  3. package/dist/docs/core/adapters/csr.md +78 -0
  4. package/dist/docs/core/adapters/custom-adapter.md +357 -0
  5. package/dist/docs/core/adapters/go-template-adapter.md +269 -0
  6. package/dist/docs/core/adapters/hono-adapter.md +199 -0
  7. package/dist/docs/core/adapters.md +37 -0
  8. package/dist/docs/core/advanced/code-splitting.md +142 -0
  9. package/dist/docs/core/advanced/compiler-internals.md +331 -0
  10. package/dist/docs/core/advanced/error-codes.md +261 -0
  11. package/dist/docs/core/advanced/ir-schema.md +65 -0
  12. package/dist/docs/core/advanced/performance.md +115 -0
  13. package/dist/docs/core/advanced/xyflow-browser-bundle.md +69 -0
  14. package/dist/docs/core/advanced.md +11 -0
  15. package/dist/docs/core/components/children-slots.md +150 -0
  16. package/dist/docs/core/components/component-authoring.md +207 -0
  17. package/dist/docs/core/components/context-api.md +236 -0
  18. package/dist/docs/core/components/portals.md +192 -0
  19. package/dist/docs/core/components/props-type-safety.md +97 -0
  20. package/dist/docs/core/components/styling.md +37 -0
  21. package/dist/docs/core/components.md +19 -0
  22. package/dist/docs/core/core-concepts/ai-native.md +83 -0
  23. package/dist/docs/core/core-concepts/backend-freedom.md +31 -0
  24. package/dist/docs/core/core-concepts/how-it-works.md +147 -0
  25. package/dist/docs/core/core-concepts/mpa-style.md +36 -0
  26. package/dist/docs/core/core-concepts/reactivity.md +35 -0
  27. package/dist/docs/core/core-concepts.md +28 -0
  28. package/dist/docs/core/introduction.md +87 -0
  29. package/dist/docs/core/llms.txt +53 -0
  30. package/dist/docs/core/quick-start.mdx +160 -0
  31. package/dist/docs/core/reactivity/create-effect.md +125 -0
  32. package/dist/docs/core/reactivity/create-memo.md +91 -0
  33. package/dist/docs/core/reactivity/create-signal.md +128 -0
  34. package/dist/docs/core/reactivity/on-cleanup.md +67 -0
  35. package/dist/docs/core/reactivity/on-mount.md +70 -0
  36. package/dist/docs/core/reactivity/props-reactivity.md +91 -0
  37. package/dist/docs/core/reactivity/untrack.md +69 -0
  38. package/dist/docs/core/reactivity.md +28 -0
  39. package/dist/docs/core/rendering/client-directive.md +82 -0
  40. package/dist/docs/core/rendering/fragment.md +43 -0
  41. package/dist/docs/core/rendering/jsx-compatibility.md +163 -0
  42. package/dist/docs/core/rendering.md +14 -0
  43. package/dist/index.js +25490 -0
  44. package/dist/tokens.json +74 -0
  45. package/package.json +37 -0
@@ -0,0 +1,147 @@
1
+ ---
2
+ title: How It Works
3
+ description: Two-phase compilation and hydration markers
4
+ ---
5
+
6
+ # How It Works
7
+
8
+ ## Two-Phase Compilation
9
+
10
+ One JSX source file produces two outputs:
11
+
12
+ ```
13
+ JSX Source
14
+
15
+ [Phase 1] Analyze + Transform → IR (Intermediate Representation)
16
+
17
+ [Phase 2a] IR → Marked Template (server)
18
+ [Phase 2b] IR → Client JS (browser)
19
+ ```
20
+
21
+ **Phase 1** produces a JSON IR tree — component structure, reactive expressions, event handlers, type information. Backend-independent.
22
+
23
+ **Phase 2** generates:
24
+
25
+ - **Marked Template** — HTML with `bf-*` attributes marking interactive elements. The adapter determines the format.
26
+ - **Client JS** — Creates signals, wires effects, binds event handlers to marked elements.
27
+
28
+ ### Counter Example
29
+
30
+ Source:
31
+
32
+ ```tsx
33
+ "use client"
34
+ import { createSignal } from '@barefootjs/client'
35
+
36
+ export function Counter() {
37
+ const [count, setCount] = createSignal(0)
38
+
39
+ return (
40
+ <button onClick={() => setCount(n => n + 1)}>
41
+ Count: {count()}
42
+ </button>
43
+ )
44
+ }
45
+ ```
46
+
47
+ The IR records:
48
+ - Signal `count` with initial value `0`
49
+ - Reactive text expression `count()` → slot `s0`
50
+ - Click handler on button → slot `s1`
51
+
52
+ Marked template (Phase 2a):
53
+
54
+ <!-- tabs:adapter -->
55
+ <!-- tab:Hono -->
56
+ ```tsx
57
+ export function Counter({ __instanceId, ... }) {
58
+ const __scopeId = __instanceId || `Counter_${Math.random().toString(36).slice(2, 8)}`
59
+ const count = () => 0 // server-side stub
60
+
61
+ return (
62
+ <button bf-s={__scopeId} bf="s1">
63
+ Count: {bfText("s0")}{count()}{bfTextEnd()}
64
+ </button>
65
+ )
66
+ }
67
+ ```
68
+ <!-- tab:Go Template -->
69
+ ```go-template
70
+ {{define "Counter"}}
71
+ <button bf-s="{{bfScopeAttr .}}" bf="s1">
72
+ Count: {{bfTextStart "s0"}}{{.Count}}{{bfTextEnd}}
73
+ </button>
74
+ {{end}}
75
+ ```
76
+ <!-- /tabs -->
77
+
78
+ Client JS (Phase 2b):
79
+
80
+ ```js
81
+ import { $, $t, createEffect, createSignal, hydrate } from '@barefootjs/client'
82
+
83
+ export function initCounter(__scope, _p = {}) {
84
+ if (!__scope) return
85
+
86
+ const [count, setCount] = createSignal(0)
87
+
88
+ const [_s1] = $(__scope, 's1') // element lookup
89
+ const [_s0] = $t(__scope, 's0') // text node lookup
90
+
91
+ createEffect(() => {
92
+ const __val = count()
93
+ if (_s0) _s0.nodeValue = String(__val ?? '')
94
+ })
95
+
96
+ if (_s1) _s1.addEventListener('click', () => { setCount(n => n + 1) })
97
+ }
98
+
99
+ hydrate('Counter', {
100
+ init: initCounter,
101
+ template: (_p) => `<button bf="s1"> Count: <!--bf:s0-->${(0)}<!--/--></button>`
102
+ })
103
+ ```
104
+
105
+ See [Compiler Internals](../advanced/compiler-internals.md) and [IR Schema Reference](../advanced/ir-schema.md).
106
+
107
+ ## Hydration
108
+
109
+ Marker-driven hydration attaches behavior to server-rendered HTML.
110
+
111
+ ### Markers
112
+
113
+ `bf-*` attributes in the marked template tell client JS where to attach:
114
+
115
+ | Marker | Purpose | Example |
116
+ |--------|---------|---------|
117
+ | `bf-s` | Component scope boundary (`~` = child) | `<div bf-s="Counter_a1b2">` |
118
+ | `bf` | Interactive element (slot) | `<p bf="s0">` |
119
+ | `bf-p` | Serialized props JSON | `<div bf-p='{"initial":5}'>` |
120
+ | `bf-c` | Conditional block | `<div bf-c="s2">` |
121
+ | `bf-po` | Portal owner scope ID | `<div bf-po="Dialog_a1b2">` |
122
+ | `bf-pi` | Portal container ID | `<div bf-pi="bf-portal-1">` |
123
+ | `bf-pp` | Portal placeholder | `<template bf-pp="bf-portal-1">` |
124
+ | `bf-i` | List item marker | `<li bf-i>` |
125
+
126
+ ### Flow
127
+
128
+ 1. Server renders HTML with markers, embeds props in `bf-p`
129
+ 2. Browser loads client JS
130
+ 3. `hydrate()` finds uninitialized `bf-s` elements
131
+ 4. Init function runs per scope — signals, effects, handlers
132
+ 5. Runtime tracks scopes to prevent double initialization
133
+
134
+ ### Scoped Queries
135
+
136
+ `$()` and `$t()` search within a scope, excluding child component scopes:
137
+
138
+ ```html
139
+ <div bf-s="TodoApp_x1">
140
+ <h1 bf="s0">Todo</h1>
141
+ <div bf-s="~TodoItem_y1">
142
+ <span bf="s0">Buy milk</span>
143
+ </div>
144
+ </div>
145
+ ```
146
+
147
+ `$(__scope, 's0')` in TodoApp finds `<h1>`, not the `<span>` inside TodoItem. The `~` prefix marks a child scope excluded from parent queries.
@@ -0,0 +1,36 @@
1
+ ---
2
+ title: MPA-style Development
3
+ description: Server-rendering by default, with client JavaScript only where you need it
4
+ ---
5
+
6
+ # MPA-style Development
7
+
8
+ Add interactive components to server-rendered pages without changing your architecture.
9
+
10
+ Existing options require trade-offs:
11
+
12
+ - **jQuery / vanilla JS** — No component model. Hard to maintain at scale.
13
+ - **SPA framework (Next.js, Nuxt)** — Even with server components, you adopt the framework's build pipeline, routing, and deployment model.
14
+ - **Islands (Astro, Fresh)** — Server rendering with selective hydration, but your server must be Astro or Fresh.
15
+
16
+ BarefootJS outputs templates for your existing server. The compiler is a build step — your routing and deployment don't change. `"use client"` marks the components that need interactivity; only those ship JavaScript:
17
+
18
+ ```tsx
19
+ // ProductPage.tsx — server component
20
+ import { AddToCart } from './AddToCart' // "use client"
21
+ import { ReviewStars } from './ReviewStars' // "use client"
22
+
23
+ export function ProductPage({ product }) {
24
+ return (
25
+ <div>
26
+ <h1>{product.name}</h1>
27
+ <p>{product.description}</p>
28
+ <img src={product.image} />
29
+ <ReviewStars rating={product.rating} />
30
+ <AddToCart productId={product.id} />
31
+ </div>
32
+ )
33
+ }
34
+ ```
35
+
36
+ `h1`, `p`, `img` produce zero JS. Only `ReviewStars` and `AddToCart` ship client JavaScript. Server-rendered HTML is visible immediately; interactive components become functional after hydration.
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: Fine-grained Reactivity
3
+ description: Signal-based reactivity — no virtual DOM, updates at the DOM node level
4
+ ---
5
+
6
+ # Fine-grained Reactivity
7
+
8
+ The compiler analyzes which DOM nodes depend on which signals and generates code that connects them at hydration. When state changes, only that DOM node updates — no virtual DOM, no component re-render.
9
+
10
+ Inspired by [SolidJS](https://www.solidjs.com/). The key difference from React: **components run once**, not on every state change.
11
+
12
+ ## Signals, Effects, Memos
13
+
14
+ ```tsx
15
+ const [count, setCount] = createSignal(0) // reactive value
16
+ const doubled = createMemo(() => count() * 2) // cached derived value
17
+
18
+ createEffect(() => {
19
+ console.log('Count is:', count()) // re-runs when count changes
20
+ })
21
+
22
+ setCount(1) // triggers the effect, recomputes doubled
23
+ ```
24
+
25
+ The getter is a function call — `count()`, not `count`. The runtime tracks which signals each effect reads. No dependency arrays.
26
+
27
+ ## How Updates Reach the DOM
28
+
29
+ ```
30
+ setCount(1) → signal notifies subscribers → effect updates the DOM node
31
+ ```
32
+
33
+ The compiler analyzed which DOM node depends on `count` and generated an effect that updates it directly. No tree diffing at runtime.
34
+
35
+ For the full API, see [Reactivity](../reactivity.md).
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Core Concepts
3
+ description: The four design principles and a technical overview of how BarefootJS works
4
+ ---
5
+
6
+ # Core Concepts
7
+
8
+ BarefootJS compiles JSX into server templates and minimal client JS for any backend. No SPA framework, no Node.js lock-in.
9
+
10
+ ## Backend Freedom
11
+
12
+ Server rendering with JSX usually means running Node.js. BarefootJS compiles JSX to native templates for Hono, Go `html/template`, or any custom adapter — no Node.js at serving time.
13
+
14
+ ## MPA-style Development
15
+
16
+ Components render to static HTML by default. `"use client"` marks those that need interactivity — only they ship JavaScript. Your routing, data fetching, and templates don't change.
17
+
18
+ ## Fine-grained Reactivity
19
+
20
+ The compiler analyzes which DOM nodes depend on which signals and generates code that connects them. When state changes, only the affected node updates — no virtual DOM, no component re-render.
21
+
22
+ ## AI-native Development
23
+
24
+ `renderToTest()` verifies component structure, signals, and accessibility against the compiler's IR in milliseconds. E2E tests are still needed for real interactions, but structural issues are caught fast. The `bf` CLI provides discovery, scaffolding, and debugging for humans and AI agents.
25
+
26
+ ## How It Works
27
+
28
+ Two-phase compilation and hydration markers — a technical deep-dive.
@@ -0,0 +1,87 @@
1
+ ---
2
+ title: Introduction
3
+ description: What is BarefootJS — JSX to server template + client JS compiler
4
+ ---
5
+
6
+ # Introduction
7
+
8
+ ## What is BarefootJS?
9
+
10
+ BarefootJS is a compiler that transforms JSX components into server-rendered templates and minimal client-side JavaScript.
11
+
12
+ Write familiar JSX with fine-grained reactivity — the compiler splits it into a **marked template** for your backend and a **tiny hydration script** for the browser.
13
+
14
+ ```tsx
15
+ "use client"
16
+ import { createSignal } from '@barefootjs/client'
17
+
18
+ export function Counter() {
19
+ const [count, setCount] = createSignal(0)
20
+
21
+ return (
22
+ <button onClick={() => setCount(n => n + 1)}>
23
+ Count: {count()}
24
+ </button>
25
+ )
26
+ }
27
+ ```
28
+
29
+ This single file compiles into two outputs:
30
+
31
+ <!-- tabs:adapter -->
32
+ <!-- tab:Hono -->
33
+ **Marked template** — Renders static HTML with hydration markers:
34
+
35
+ ```tsx
36
+ export function Counter({ __instanceId, ... }) {
37
+ const __scopeId = __instanceId || `Counter_${Math.random().toString(36).slice(2, 8)}`
38
+ const count = () => 0
39
+
40
+ return (
41
+ <button bf-s={__scopeId} bf="s1">
42
+ Count: {bfText("s0")}{count()}{bfTextEnd()}
43
+ </button>
44
+ )
45
+ }
46
+ ```
47
+
48
+ <!-- tab:Go Template -->
49
+ **Marked template** — Go `html/template` with hydration markers:
50
+
51
+ ```go-template
52
+ {{define "Counter"}}
53
+ <button bf-s="{{bfScopeAttr .}}" bf="s1">
54
+ Count: {{bfTextStart "s0"}}{{.Count}}{{bfTextEnd}}
55
+ </button>
56
+ {{end}}
57
+ ```
58
+
59
+ <!-- /tabs -->
60
+
61
+ **Client script** — Wires up only the interactive parts:
62
+
63
+ ```js
64
+ import { $, $t, createEffect, createSignal, hydrate } from '@barefootjs/client'
65
+
66
+ export function initCounter(__scope, _p = {}) {
67
+ if (!__scope) return
68
+
69
+ const [count, setCount] = createSignal(0)
70
+
71
+ const [_s1] = $(__scope, 's1') // find element with bf="s1"
72
+ const [_s0] = $t(__scope, 's0') // find text node at <!--bf:s0-->
73
+
74
+ createEffect(() => {
75
+ const __val = count()
76
+ if (_s0) _s0.nodeValue = String(__val ?? '')
77
+ })
78
+
79
+ if (_s1) _s1.addEventListener('click', () => { setCount(n => n + 1) })
80
+ }
81
+
82
+ hydrate('Counter', {
83
+ init: initCounter,
84
+ template: (_p) => `<button bf="s1"> Count: <!--bf:s0-->${(0)}<!--/--></button>`
85
+ })
86
+ ```
87
+
@@ -0,0 +1,53 @@
1
+ # BarefootJS
2
+
3
+ > JSX -> Marked Template + client JS compiler. Signal-based reactivity for any backend.
4
+
5
+ ## Core Concepts
6
+
7
+ - [AI-native Development](https://barefootjs.dev/docs/core-concepts/ai-native.md): Millisecond IR tests and the bf CLI for human + agent workflows
8
+ - [Backend Freedom](https://barefootjs.dev/docs/core-concepts/backend-freedom.md): How adapters let the same JSX run on any server — Hono, Go, and beyond
9
+ - [How It Works](https://barefootjs.dev/docs/core-concepts/how-it-works.md): Two-phase compilation and hydration markers
10
+ - [MPA-style Development](https://barefootjs.dev/docs/core-concepts/mpa-style.md): Server-rendering by default, with client JavaScript only where you need it
11
+ - [Fine-grained Reactivity](https://barefootjs.dev/docs/core-concepts/reactivity.md): Signal-based reactivity — no virtual DOM, updates at the DOM node level
12
+
13
+ ## Reactivity
14
+
15
+ - [createEffect](https://barefootjs.dev/docs/reactivity/create-effect.md): Runs a function and re-runs it whenever its tracked signal dependencies change.
16
+ - [createMemo](https://barefootjs.dev/docs/reactivity/create-memo.md): Creates a cached derived value that recomputes only when its dependencies change.
17
+ - [createSignal](https://barefootjs.dev/docs/reactivity/create-signal.md): Creates a reactive getter/setter pair for managing state.
18
+ - [onCleanup](https://barefootjs.dev/docs/reactivity/on-cleanup.md): Registers a cleanup function that runs when the owning effect re-runs or the component is destroyed.
19
+ - [onMount](https://barefootjs.dev/docs/reactivity/on-mount.md): Runs a callback once when the component initializes, without tracking signal dependencies.
20
+ - [Props Reactivity](https://barefootjs.dev/docs/reactivity/props-reactivity.md): How prop access patterns determine whether reactive updates propagate in BarefootJS components.
21
+ - [untrack](https://barefootjs.dev/docs/reactivity/untrack.md): Executes a function without tracking signal dependencies in the current reactive context.
22
+
23
+ ## Rendering
24
+
25
+ - [/* @client */ Directive](https://barefootjs.dev/docs/rendering/client-directive.md): Mark JSX expressions for client-only evaluation when the compiler cannot translate them to server templates.
26
+ - [Fragment](https://barefootjs.dev/docs/rendering/fragment.md): Using fragments to render children without a wrapper element, including transparent fragment behavior.
27
+ - [JSX Compatibility](https://barefootjs.dev/docs/rendering/jsx-compatibility.md): Standard JSX syntax support in BarefootJS, including control flow and common patterns from React and SolidJS.
28
+
29
+ ## Components
30
+
31
+ - [Children & Slots](https://barefootjs.dev/docs/components/children-slots.md): Accept nested JSX content via the children prop and enable polymorphic rendering with the Slot component.
32
+ - [Component Authoring](https://barefootjs.dev/docs/components/component-authoring.md): Learn how to write server and client components in BarefootJS using JSX functions.
33
+ - [Context API](https://barefootjs.dev/docs/components/context-api.md): Share state with deeply nested children without prop drilling using createContext and useContext.
34
+ - [Portals](https://barefootjs.dev/docs/components/portals.md): Render elements outside their parent DOM hierarchy for overlays, modals, and tooltips.
35
+ - [Props & Type Safety](https://barefootjs.dev/docs/components/props-type-safety.md): Type component props with TypeScript interfaces and preserve type information through compilation.
36
+ - [Style Overrides](https://barefootjs.dev/docs/components/styling.md): How user-supplied classes override component base classes via CSS Cascade Layers
37
+
38
+ ## Adapters
39
+
40
+ - [Adapter Architecture](https://barefootjs.dev/docs/adapters/adapter-architecture.md): How adapters convert the compiler's IR into server-renderable template formats.
41
+ - [CSR (Client-Side Rendering)](https://barefootjs.dev/docs/adapters/csr.md): Render BarefootJS components directly in the browser without a server-rendered template.
42
+ - [Writing a Custom Adapter](https://barefootjs.dev/docs/adapters/custom-adapter.md): Step-by-step guide to building a custom adapter using the TestAdapter as a reference.
43
+ - [Go Template Adapter](https://barefootjs.dev/docs/adapters/go-template-adapter.md): Generate Go html/template files and type definitions from the compiler's IR.
44
+ - [Hono Adapter](https://barefootjs.dev/docs/adapters/hono-adapter.md): Generate Hono JSX templates from the compiler's IR for Hono-based servers.
45
+
46
+ ## Advanced
47
+
48
+ - [Vendor code-splitting](https://barefootjs.dev/docs/advanced/code-splitting.md): Split large vendor libraries into separately-cached browser chunks via barefoot.config.ts externals
49
+ - [Compiler Internals](https://barefootjs.dev/docs/advanced/compiler-internals.md): How the BarefootJS compiler transforms JSX into marked templates and client JavaScript.
50
+ - [Error Codes Reference](https://barefootjs.dev/docs/advanced/error-codes.md): BF-prefixed compiler error codes with explanations and fixes.
51
+ - [IR Schema Reference](https://barefootjs.dev/docs/advanced/ir-schema.md): JSON tree structure of the Intermediate Representation consumed by adapters and client-JS generation.
52
+ - [Performance Optimization](https://barefootjs.dev/docs/advanced/performance.md): Strategies to minimize bundle size, reduce hydration cost, and optimize runtime reactivity
53
+ - [xyflow browser bundle](https://barefootjs.dev/docs/advanced/xyflow-browser-bundle.md): How to serve @barefootjs/xyflow as a pre-built browser chunk via an importmap
@@ -0,0 +1,160 @@
1
+ ---
2
+ title: Quick Start
3
+ description: Scaffold a BarefootJS app in under five minutes — Counter component, dev server, deploy.
4
+ ---
5
+
6
+ # Quick Start
7
+
8
+ Scaffold a BarefootJS app, run it locally, and tour the generated project. About five minutes.
9
+
10
+ ## Prerequisites
11
+
12
+ - **Node.js 22+** (or Bun).
13
+ - The default scaffold targets [Cloudflare Workers](https://developers.cloudflare.com/workers/) via `wrangler dev` — runs locally, no account needed.
14
+
15
+ ## 1. Scaffold the project
16
+
17
+ <PackageManagerTabs command="barefootjs@latest" mode="create" />
18
+
19
+ Press Enter at the prompts to accept the defaults (Hono on Cloudflare Workers, UnoCSS).
20
+
21
+ ## 2. Install and run
22
+
23
+ ```bash
24
+ cd my-app
25
+ npm install
26
+ npm run dev
27
+ ```
28
+
29
+ `npm run dev` runs three processes in parallel:
30
+
31
+ - `bf build --watch` — the BarefootJS compiler. Watches `components/` and emits marked templates plus client JS to `public/components/`.
32
+ - `unocss --watch` — scans your JSX for utility classes and writes `public/uno.css`.
33
+ - `wrangler dev --live-reload` — Cloudflare's local Workers runtime. Serves the app and reloads the browser on rebuilds.
34
+
35
+ Open the URL Wrangler prints. You should see a counter card with **+1**, **-1**, and **Reset** buttons.
36
+
37
+ ## 3. Look at what was generated
38
+
39
+ ```
40
+ my-app/
41
+ ├── server.tsx # Hono routes — entry point
42
+ ├── renderer.tsx # HTML shell (<head>, <body>, BfScripts)
43
+ ├── components/
44
+ │ └── Counter.tsx # The starter component
45
+ ├── components/ui/
46
+ │ └── button/ # Pulled from the BarefootJS UI registry
47
+ ├── public/ # Static assets served by Workers
48
+ │ ├── tokens.css # CSS design tokens
49
+ │ ├── styles.css # Counter + page styles
50
+ │ └── components/ # Generated client JS (bf build writes here)
51
+ ├── barefoot.config.ts # Compiler + paths config
52
+ ├── wrangler.jsonc # Cloudflare Workers config
53
+ └── uno.config.ts # UnoCSS scan patterns
54
+ ```
55
+
56
+ Open `components/Counter.tsx`:
57
+
58
+ ```tsx
59
+ 'use client'
60
+
61
+ import { createSignal, createMemo } from '@barefootjs/client'
62
+ import { Button } from '@/components/ui/button'
63
+
64
+ interface CounterProps {
65
+ initial?: number
66
+ }
67
+
68
+ export function Counter(props: CounterProps) {
69
+ const [count, setCount] = createSignal(props.initial ?? 0)
70
+ const doubled = createMemo(() => count() * 2)
71
+
72
+ return (
73
+ <div className="counter">
74
+ <p className="counter-value">count: {count()}</p>
75
+ <p className="counter-doubled">doubled: {doubled()}</p>
76
+ <div className="counter-buttons">
77
+ <Button onClick={() => setCount(n => n + 1)}>+1</Button>
78
+ <Button onClick={() => setCount(n => n - 1)} variant="secondary">-1</Button>
79
+ <Button onClick={() => setCount(0)} variant="ghost">Reset</Button>
80
+ </div>
81
+ </div>
82
+ )
83
+ }
84
+ ```
85
+
86
+ See [Client Directive](./rendering/client-directive.md), [`createSignal`](./reactivity/create-signal.md), and [`createMemo`](./reactivity/create-memo.md) for what each piece does. Props are read via `props.initial`, not destructured — destructuring captures the value once and breaks reactivity, so the compiler emits warning [`BF043`](./advanced/error-codes.md) when it sees that form on a `"use client"` component. [Props Reactivity](./reactivity/props-reactivity.md) covers the full rule.
87
+
88
+ The Counter is mounted in `server.tsx`:
89
+
90
+ ```tsx
91
+ import { Hono } from 'hono'
92
+ import { renderer } from './renderer'
93
+ import { Counter } from '@/components/Counter'
94
+
95
+ const app = new Hono()
96
+
97
+ app.use('*', renderer)
98
+
99
+ app.get('/', (c) =>
100
+ c.render(
101
+ <main>
102
+ <Counter />
103
+ </main>,
104
+ { title: 'BarefootJS app' },
105
+ ),
106
+ )
107
+
108
+ export default app
109
+ ```
110
+
111
+ Same `Counter` import, two outputs: server renders HTML, client hydrates the buttons.
112
+
113
+ ## 4. Make a change
114
+
115
+ With `npm run dev` still running, pass an initial value from the server. In `server.tsx`:
116
+
117
+ ```tsx
118
+ app.get('/', (c) =>
119
+ c.render(
120
+ <main>
121
+ <Counter initial={5} />
122
+ </main>,
123
+ { title: 'BarefootJS app' },
124
+ ),
125
+ )
126
+ ```
127
+
128
+ Save. The browser reloads and the counter starts at **5**. The server rendered `5` into the HTML, and hydration picked it up on the client — the same JSX, evaluated in both places.
129
+
130
+ Now add a new button to `Counter.tsx`:
131
+
132
+ ```tsx
133
+ <Button onClick={() => setCount(n => n * 2)} variant="ghost">×2</Button>
134
+ ```
135
+
136
+ Save and watch the browser update. No virtual DOM, no diff — the compiler generated an effect that updates only the `<p>` text node when `count` changes.
137
+
138
+ ## 5. Deploy (optional)
139
+
140
+ When you're ready to ship:
141
+
142
+ ```bash
143
+ npm run deploy
144
+ ```
145
+
146
+ This runs `bf build`, generates the final `uno.css`, and calls `wrangler deploy`. The first deploy will prompt you to log into Cloudflare. After that, your app is live on `*.workers.dev`.
147
+
148
+ ## Next steps
149
+
150
+ - **[Core Concepts](./core-concepts.md)** — the four design principles behind BarefootJS: backend freedom, MPA-style rendering, fine-grained reactivity, and AI-native workflows.
151
+ - **[`createSignal`](./reactivity/create-signal.md)** and **[`createMemo`](./reactivity/create-memo.md)** — the reactivity primitives you just used.
152
+ - **[Client Directive](./rendering/client-directive.md)** — exactly what `"use client"` does and when to reach for it.
153
+ - **[Hono Adapter](./adapters/hono-adapter.md)** — adapter-specific configuration and output details.
154
+ - Pick a different backend by passing `--adapter` to the scaffolder. Supported values today: `hono` (default — Cloudflare Workers), `hono-node`, `echo` (Go / Echo), `mojo` (Mojolicious / Perl), `csr` (no backend — pure client render). For example:
155
+
156
+ ```bash
157
+ npm create barefootjs@latest -- --adapter hono-node
158
+ ```
159
+
160
+ See [Adapter Architecture](./adapters/adapter-architecture.md) for the architectural overview, and the per-adapter pages under [`docs/core/adapters/`](./adapters/) for output details. The `@barefootjs/go-template` package is a compile-time adapter API for generating Go `html/template` files — it does not have a `bf init` scaffold; see [Go Template Adapter](./adapters/go-template-adapter.md) for the programmatic usage.
@@ -0,0 +1,125 @@
1
+ ---
2
+ title: createEffect
3
+ description: Runs a function and re-runs it whenever its tracked signal dependencies change.
4
+ ---
5
+
6
+ # createEffect
7
+
8
+ Runs a function immediately and re-runs it whenever any signal read inside it changes.
9
+
10
+ ```tsx
11
+ import { createEffect } from '@barefootjs/client'
12
+
13
+ createEffect(fn: () => void | (() => void)): void
14
+ ```
15
+
16
+
17
+ ## Basic Usage
18
+
19
+ ```tsx
20
+ const [count, setCount] = createSignal(0)
21
+
22
+ createEffect(() => {
23
+ document.title = `Count: ${count()}`
24
+ })
25
+
26
+ setCount(1) // Effect re-runs, title becomes "Count: 1"
27
+ ```
28
+
29
+ Dependencies are tracked automatically. No dependency array is needed.
30
+
31
+
32
+ ## Conditional Dependencies
33
+
34
+ Dependencies change per run. If a branch skips a signal read, that signal is not tracked for that run:
35
+
36
+ ```tsx
37
+ const [showName, setShowName] = createSignal(true)
38
+ const [name, setName] = createSignal('Alice')
39
+ const [count, setCount] = createSignal(0)
40
+
41
+ createEffect(() => {
42
+ if (showName()) {
43
+ console.log(name()) // name is tracked
44
+ } else {
45
+ console.log(count()) // count is tracked instead
46
+ }
47
+ })
48
+ ```
49
+
50
+
51
+ ## Cleanup
52
+
53
+ Two ways to register cleanup for resources that need teardown before re-run.
54
+
55
+ ### Return a function
56
+
57
+ ```tsx
58
+ createEffect(() => {
59
+ const timer = setInterval(() => console.log('tick'), 1000)
60
+ return () => clearInterval(timer)
61
+ })
62
+ ```
63
+
64
+ ### `onCleanup`
65
+
66
+ ```tsx
67
+ createEffect(() => {
68
+ const timer = setInterval(() => console.log('tick'), 1000)
69
+ onCleanup(() => clearInterval(timer))
70
+ })
71
+ ```
72
+
73
+ `onCleanup` can be called multiple times. Cleanups run in reverse order (last registered, first called). See [`onCleanup`](./on-cleanup.md) for details.
74
+
75
+
76
+ ## Common Patterns
77
+
78
+ ### localStorage sync
79
+
80
+ ```tsx
81
+ const [theme, setTheme] = createSignal('light')
82
+
83
+ createEffect(() => {
84
+ localStorage.setItem('theme', theme())
85
+ })
86
+ ```
87
+
88
+ ### Data fetching
89
+
90
+ ```tsx
91
+ const [query, setQuery] = createSignal('')
92
+
93
+ createEffect(() => {
94
+ const q = query()
95
+ if (!q) return
96
+
97
+ const controller = new AbortController()
98
+ fetch(`/api/search?q=${q}`, { signal: controller.signal })
99
+ .then(r => r.json())
100
+ .then(setResults)
101
+
102
+ onCleanup(() => controller.abort())
103
+ })
104
+ ```
105
+
106
+ When `query` changes, the previous fetch is aborted before the new one starts.
107
+
108
+ ### Reactive attributes
109
+
110
+ The compiler generates effects for reactive attributes.
111
+
112
+ Source:
113
+
114
+ ```tsx
115
+ <button disabled={loading()}>Submit</button>
116
+ ```
117
+
118
+ Generated client JS:
119
+
120
+ ```js
121
+ const [_s0] = $(__scope, 's0')
122
+ createEffect(() => {
123
+ if (_s0) { _s0.disabled = !!(loading()) }
124
+ })
125
+ ```