@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,115 @@
1
+ ---
2
+ title: Performance Optimization
3
+ description: Strategies to minimize bundle size, reduce hydration cost, and optimize runtime reactivity
4
+ ---
5
+
6
+ # Performance Optimization
7
+
8
+ ## Zero-JS by Default
9
+
10
+ Components without `"use client"` generate **no client JavaScript**:
11
+
12
+ ```tsx
13
+ // Server-only — 0 bytes of client JS
14
+ export function Header() {
15
+ return (
16
+ <header>
17
+ <h1>My App</h1>
18
+ <nav>...</nav>
19
+ </header>
20
+ )
21
+ }
22
+ ```
23
+
24
+ ## Minimal Hydration
25
+
26
+ Only signals, event handlers, and effects are sent to the client. The HTML structure is never re-created — the server already rendered it.
27
+
28
+ ---
29
+
30
+ ## Reducing Client JS Size
31
+
32
+ ### Use Memos for Derived Values
33
+
34
+ ```tsx
35
+ // ❌ Redundant signal
36
+ const [count, setCount] = createSignal(0)
37
+ const [doubled, setDoubled] = createSignal(0)
38
+ createEffect(() => setDoubled(count() * 2)) // Extra signal + effect
39
+
40
+ // ✅ Use memo instead
41
+ const [count, setCount] = createSignal(0)
42
+ const doubled = createMemo(() => count() * 2) // Computed, no extra signal
43
+ ```
44
+
45
+ ### Prefer Static Arrays
46
+
47
+ The compiler detects static arrays and skips reconciliation:
48
+
49
+ ```tsx
50
+ // Static — no reconciliation generated
51
+ const tabs = ['Home', 'About', 'Contact']
52
+ {tabs.map(tab => <Tab label={tab} />)}
53
+
54
+ // Dynamic — reconcileElements needed
55
+ const [items, setItems] = createSignal([...])
56
+ {items().map(item => <Item key={item.id} data={item} />)}
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Optimizing Hydration
62
+
63
+ ### Stable Keys for Lists
64
+
65
+ ```tsx
66
+ // ✅ Stable key — DOM nodes reused when list changes
67
+ {items().map(item => <li key={item.id}>{item.name}</li>)}
68
+
69
+ // ❌ Index key — DOM nodes recreated on reorder
70
+ {items().map((item, i) => <li key={i}>{item.name}</li>)}
71
+ ```
72
+
73
+ ### Focus Preservation
74
+
75
+ The reconciler preserves focused elements during list updates automatically.
76
+
77
+ ---
78
+
79
+ ## Optimizing Reactivity
80
+
81
+ ### `untrack` for One-Time Reads
82
+
83
+ ```tsx
84
+ createEffect(() => {
85
+ // Only re-runs when items() changes, not when count() changes
86
+ const currentCount = untrack(() => count())
87
+ console.log(`${items().length} items, count was ${currentCount}`)
88
+ })
89
+ ```
90
+
91
+ ### Memo Over Effect + Signal
92
+
93
+ ```tsx
94
+ // ❌ Effect → Signal chain (two subscriptions)
95
+ const [total, setTotal] = createSignal(0)
96
+ createEffect(() => setTotal(price() * quantity()))
97
+
98
+ // ✅ Single memo (one subscription)
99
+ const total = createMemo(() => price() * quantity())
100
+ ```
101
+
102
+ ### Guard DOM Updates
103
+
104
+ ```tsx
105
+ createEffect(() => {
106
+ const cls = isActive() ? 'active' : 'inactive'
107
+ if (element.className !== cls) {
108
+ element.className = cls // Only touches DOM when value changes
109
+ }
110
+ })
111
+ ```
112
+
113
+ The compiler already generates guarded updates for text content and common attributes. This applies to custom effects only.
114
+
115
+
@@ -0,0 +1,69 @@
1
+ ---
2
+ title: xyflow browser bundle
3
+ description: How to serve @barefootjs/xyflow as a pre-built browser chunk via an importmap
4
+ ---
5
+
6
+ # xyflow browser bundle
7
+
8
+ `@barefootjs/xyflow` ships a pre-minified ESM variant, `dist/xyflow.browser.min.js`, with `@barefootjs/client*` left as externals. Apps that want to serve xyflow as an independently-cached static asset can copy this file instead of re-bundling.
9
+
10
+ ## Why a pre-built variant
11
+
12
+ Bundling xyflow into a large client entry adds ~270 KB of d3 + wrapper code to every cold-visit payload. Re-bundling it manually as a separate chunk requires remembering three externals:
13
+
14
+ ```
15
+ --external '@barefootjs/client'
16
+ --external '@barefootjs/client/runtime'
17
+ --external '@barefootjs/client/reactive'
18
+ ```
19
+
20
+ Missing any one of them silently inlines a second copy of the reactive primitives, breaking signal propagation across the boundary (fitView becomes a no-op, `FlowContext` reads from the wrong owner, etc.). The pre-built variant has all three applied already.
21
+
22
+ ## Setup
23
+
24
+ **1. Copy the file into your static output:**
25
+
26
+ ```sh
27
+ cp node_modules/@barefootjs/xyflow/dist/xyflow.browser.min.js \
28
+ public/static/components/xyflow.js
29
+
30
+ # Optional: copy the sourcemap for readable DevTools stacks
31
+ cp node_modules/@barefootjs/xyflow/dist/xyflow.browser.min.js.map \
32
+ public/static/components/xyflow.js.map
33
+ ```
34
+
35
+ **2. Add an importmap to your HTML:**
36
+
37
+ ```html
38
+ <script type="importmap">
39
+ {
40
+ "imports": {
41
+ "@barefootjs/client": "/static/components/barefoot.js",
42
+ "@barefootjs/client/runtime": "/static/components/barefoot.js",
43
+ "@barefootjs/client/reactive": "/static/components/barefoot.js",
44
+ "@barefootjs/xyflow": "/static/components/xyflow.js"
45
+ }
46
+ }
47
+ </script>
48
+ ```
49
+
50
+ The three `@barefootjs/client*` entries all pointing at the same file is what makes the browser deduplicate them into a single module instance, so reactive primitives share one `Listener`/`Owner` global.
51
+
52
+ ## package.json fields
53
+
54
+ The file is also exposed via the `umd` export condition and the `unpkg`/`jsdelivr` top-level fields:
55
+
56
+ ```json
57
+ {
58
+ "exports": {
59
+ ".": {
60
+ "umd": "./dist/xyflow.browser.min.js",
61
+ "import": "./dist/index.js"
62
+ }
63
+ },
64
+ "unpkg": "./dist/xyflow.browser.min.js",
65
+ "jsdelivr": "./dist/xyflow.browser.min.js"
66
+ }
67
+ ```
68
+
69
+ CDNs like unpkg and jsDelivr resolve the top-level fields automatically, so `https://unpkg.com/@barefootjs/xyflow` serves the pre-built variant.
@@ -0,0 +1,11 @@
1
+ ---
2
+ title: Advanced
3
+ description: Compiler internals, IR schema, error codes, and performance optimization for contributors and adapter authors.
4
+ ---
5
+
6
+ # Advanced
7
+
8
+ - [IR Schema Reference](./advanced/ir-schema.md) — The intermediate representation node types and metadata
9
+ - [Compiler Internals](./advanced/compiler-internals.md) — Pipeline phases, reactivity analysis, and code generation
10
+ - [Error Codes Reference](./advanced/error-codes.md) — All compiler errors and warnings with solutions
11
+ - [Performance Optimization](./advanced/performance.md) — Best practices for minimal client JS and fast hydration
@@ -0,0 +1,150 @@
1
+ ---
2
+ title: Children & Slots
3
+ description: Accept nested JSX content via the children prop and enable polymorphic rendering with the Slot component.
4
+ ---
5
+
6
+ # Children & Slots
7
+
8
+ Nested JSX content is passed via the `children` prop. The `Slot` component enables polymorphic rendering with `asChild`.
9
+
10
+
11
+ ## Children
12
+
13
+ ```tsx
14
+ <Card>
15
+ <h2>Title</h2>
16
+ <p>Body text</p>
17
+ </Card>
18
+ ```
19
+
20
+ ```tsx
21
+ function Card(props: { children?: Child }) {
22
+ return <div className="card">{props.children}</div>
23
+ }
24
+ ```
25
+
26
+ `children` is typed as `Child`, which covers JSX elements, strings, numbers, and arrays.
27
+
28
+
29
+ ## Passing Children Through
30
+
31
+ ```tsx
32
+ function Panel(props: { title: string; children?: Child }) {
33
+ return (
34
+ <section>
35
+ <h2>{props.title}</h2>
36
+ <div className="panel-body">{props.children}</div>
37
+ </section>
38
+ )
39
+ }
40
+ ```
41
+
42
+ Wrapping `children` in a fragment (`<>{props.children}</>`) is **transparent** — the compiler skips the fragment without extra hydration markers. See [Fragment](../rendering/fragment.md).
43
+
44
+
45
+ ## The `Slot` Component
46
+
47
+ `Slot` merges props and classes onto its child element, enabling the **`asChild` pattern**:
48
+
49
+ ```tsx
50
+ import { Slot } from './slot'
51
+
52
+ function Button({ className, asChild, children, ...props }: ButtonProps) {
53
+ const classes = `btn btn-primary ${className}`
54
+
55
+ if (asChild) {
56
+ return <Slot className={classes} {...props}>{children}</Slot>
57
+ }
58
+ return <button className={classes} {...props}>{children}</button>
59
+ }
60
+ ```
61
+
62
+ ### How `Slot` Works
63
+
64
+ `Slot` extracts the child's tag, merges `className` (space-separated), spreads remaining props, and renders the child's tag with the merged result.
65
+
66
+ ```tsx
67
+ // Input
68
+ <Slot className="btn" onClick={handleClick}>
69
+ <a href="/home">Home</a>
70
+ </Slot>
71
+
72
+ // Output
73
+ <a href="/home" className="btn" onClick={handleClick}>Home</a>
74
+ ```
75
+
76
+ If `children` is not a valid element (e.g., a string), `Slot` falls back to rendering it inside a fragment.
77
+
78
+
79
+ ## The `asChild` Pattern
80
+
81
+ `asChild` delegates rendering to the child element — the component's styling without its default HTML tag.
82
+
83
+ ### Default rendering (no `asChild`)
84
+
85
+ ```tsx
86
+ <Button variant="primary">Click me</Button>
87
+ // Renders: <button className="btn btn-primary">Click me</button>
88
+ ```
89
+
90
+ ### With `asChild`
91
+
92
+ ```tsx
93
+ <Button variant="primary" asChild>
94
+ <a href="/dashboard">Go to Dashboard</a>
95
+ </Button>
96
+ // Renders: <a href="/dashboard" className="btn btn-primary">Go to Dashboard</a>
97
+ ```
98
+
99
+ The `<a>` tag receives Button's classes and props. The component controls styling; the caller controls the element.
100
+
101
+ ### When to Use `asChild`
102
+
103
+ - Navigation buttons (render `<a>` with button styling)
104
+ - Custom triggers (dialog or dropdown)
105
+ - Semantic elements with reused component styles
106
+
107
+ ```tsx
108
+ // Dialog trigger as a custom element
109
+ <DialogTrigger asChild>
110
+ <span role="button" tabIndex={0}>Open</span>
111
+ </DialogTrigger>
112
+ ```
113
+
114
+
115
+ ## Compound Components
116
+
117
+ ```tsx
118
+ <Dialog open={open()} onOpenChange={setOpen}>
119
+ <DialogTrigger>Open</DialogTrigger>
120
+ <DialogOverlay />
121
+ <DialogContent>
122
+ <DialogHeader>
123
+ <DialogTitle>Confirm</DialogTitle>
124
+ <DialogDescription>Are you sure?</DialogDescription>
125
+ </DialogHeader>
126
+ <DialogFooter>
127
+ <DialogClose>Cancel</DialogClose>
128
+ <Button onClick={handleConfirm}>Yes</Button>
129
+ </DialogFooter>
130
+ </DialogContent>
131
+ </Dialog>
132
+ ```
133
+
134
+ Sub-components read shared state from a context provider. See [Context API](./context-api.md).
135
+
136
+
137
+ ## List Rendering
138
+
139
+ ```tsx
140
+ {todos().map(todo => (
141
+ <TodoItem
142
+ key={todo.id}
143
+ todo={todo}
144
+ onToggle={() => handleToggle(todo.id)}
145
+ onDelete={() => handleDelete(todo.id)}
146
+ />
147
+ ))}
148
+ ```
149
+
150
+ `key` is required for efficient list updates (warning `BF023` if missing).
@@ -0,0 +1,207 @@
1
+ ---
2
+ title: Component Authoring
3
+ description: Learn how to write server and client components in BarefootJS using JSX functions.
4
+ ---
5
+
6
+ # Component Authoring
7
+
8
+ Components are functions that return JSX, in two kinds: **server components** and **client components**.
9
+
10
+
11
+ ## Server Components
12
+
13
+ Server components render HTML on the server with no client-side JavaScript.
14
+
15
+ ```tsx
16
+ export function Greeting({ name }: { name: string }) {
17
+ return <h1>Hello, {name}</h1>
18
+ }
19
+ ```
20
+
21
+ Server components can access databases, read files, and use secrets. They produce a template rendered once per request.
22
+
23
+
24
+ ## Client Components
25
+
26
+ Client components use reactive primitives and ship JavaScript to the browser. They require the `"use client"` directive:
27
+
28
+ ```tsx
29
+ "use client"
30
+ import { createSignal } from '@barefootjs/client'
31
+
32
+ export function Counter() {
33
+ const [count, setCount] = createSignal(0)
34
+
35
+ return (
36
+ <button onClick={() => setCount(n => n + 1)}>
37
+ Count: {count()}
38
+ </button>
39
+ )
40
+ }
41
+ ```
42
+
43
+ The compiler produces a **marked template** (server HTML with `bf-*` attributes) and **client JS** (signals, effects, event handlers). See [How It Works](../core-concepts/how-it-works.md#two-phase-compilation) for details.
44
+
45
+ ### When `"use client"` Is Required
46
+
47
+ Add `"use client"` when a component uses:
48
+
49
+ - `createSignal`, `createEffect`, `createMemo`
50
+ - `onMount`, `onCleanup`, `untrack`
51
+ - `createContext`, `useContext`
52
+ - Event handlers (`onClick`, `onChange`, etc.)
53
+
54
+ Without the directive:
55
+
56
+ ```
57
+ error[BF001]: 'use client' directive required for components with createSignal
58
+ ```
59
+
60
+
61
+ ## Component Naming
62
+
63
+ Component names must start with an uppercase letter:
64
+
65
+ ```tsx
66
+ // ✅ Component
67
+ function TodoItem() { ... }
68
+
69
+ // ❌ Error BF042
70
+ function todoItem() { ... }
71
+ ```
72
+
73
+
74
+ ## Compilation Output
75
+
76
+ **Source:**
77
+
78
+ ```tsx
79
+ "use client"
80
+ import { createSignal } from '@barefootjs/client'
81
+
82
+ export function Toggle() {
83
+ const [on, setOn] = createSignal(false)
84
+
85
+ return (
86
+ <button onClick={() => setOn(prev => !prev)}>
87
+ {on() ? 'ON' : 'OFF'}
88
+ </button>
89
+ )
90
+ }
91
+ ```
92
+
93
+ **Marked template:**
94
+
95
+ <!-- tabs:adapter -->
96
+ <!-- tab:Hono -->
97
+ ```tsx
98
+ export function Toggle({ __instanceId, ... }) {
99
+ const __scopeId = __instanceId || `Toggle_${...}`
100
+ const on = () => false
101
+
102
+ return (
103
+ <button bf-s={__scopeId} bf="s1">
104
+ {on() ? <>{bfComment("cond-start:s0")}{'ON'}{bfComment("cond-end:s0")}</>
105
+ : <>{bfComment("cond-start:s0")}{'OFF'}{bfComment("cond-end:s0")}</>}
106
+ </button>
107
+ )
108
+ }
109
+ ```
110
+ <!-- tab:Go Template -->
111
+ ```go-template
112
+ {{define "Toggle"}}
113
+ <button bf-s="{{bfScopeAttr .}}" bf="s1">
114
+ {{if .On}}{{bfComment "cond-start:s0"}}{{"ON"}}{{bfComment "cond-end:s0"}}
115
+ {{else}}{{bfComment "cond-start:s0"}}{{"OFF"}}{{bfComment "cond-end:s0"}}{{end}}
116
+ </button>
117
+ {{end}}
118
+ ```
119
+ <!-- /tabs -->
120
+
121
+ **Client JS:**
122
+
123
+ ```js
124
+ import { $, createSignal, hydrate, insert } from '@barefootjs/client'
125
+
126
+ export function initToggle(__scope, _p = {}) {
127
+ if (!__scope) return
128
+
129
+ const [on, setOn] = createSignal(false)
130
+
131
+ const [_s1, _s0] = $(__scope, 's1', 's0')
132
+
133
+ insert(__scope, 's0', () => on(), {
134
+ template: () => `<!--bf-cond-start:s0-->ON<!--bf-cond-end:s0-->`,
135
+ bindEvents: (__branchScope) => {}
136
+ }, {
137
+ template: () => `<!--bf-cond-start:s0-->OFF<!--bf-cond-end:s0-->`,
138
+ bindEvents: (__branchScope) => {}
139
+ })
140
+
141
+ if (_s1) _s1.addEventListener('click', () => { setOn(prev => !prev) })
142
+ }
143
+
144
+ hydrate('Toggle', { init: initToggle, template: ... })
145
+ ```
146
+
147
+ Only the conditional branch bound to `on()` updates when the signal changes. The `insert()` function handles DOM swapping using comment markers as boundaries.
148
+
149
+
150
+ ## Composition Rules
151
+
152
+ | From | To | Allowed |
153
+ |------|----|---------|
154
+ | Server component | Server component | ✅ |
155
+ | Server component | Client component | ✅ |
156
+ | Client component | Client component | ✅ |
157
+ | Client component | Server component | ❌ |
158
+
159
+ Server-only code does not exist in the browser. The compiler emits `BF003` if a client component imports a server component.
160
+
161
+ ```tsx
162
+ // Page.tsx — server component
163
+ import { Counter } from './Counter' // "use client" ✅
164
+ import { UserList } from './UserList' // server-only ✅
165
+
166
+ export function Page() {
167
+ return (
168
+ <div>
169
+ <UserList /> {/* Server → Server */}
170
+ <Counter /> {/* Server → Client */}
171
+ </div>
172
+ )
173
+ }
174
+ ```
175
+
176
+ ```tsx
177
+ // Dashboard.tsx — "use client"
178
+ import { Counter } from './Counter' // ✅ Client → Client
179
+ import { UserList } from './UserList' // ❌ BF003: Client → Server
180
+ ```
181
+
182
+ ## Ref Callbacks
183
+
184
+ `ref` callbacks provide imperative DOM access. The callback receives the element after mount:
185
+
186
+ ```tsx
187
+ "use client"
188
+ import { createEffect } from '@barefootjs/client'
189
+
190
+ export function AutoFocus() {
191
+ const handleMount = (el: HTMLInputElement) => {
192
+ el.focus()
193
+ }
194
+
195
+ return <input ref={handleMount} placeholder="Focused on mount" />
196
+ }
197
+ ```
198
+
199
+ Combine with `createEffect` for reactive DOM updates:
200
+
201
+ ```tsx
202
+ const handleMount = (el: HTMLElement) => {
203
+ createEffect(() => {
204
+ el.className = isActive() ? 'active' : 'inactive'
205
+ })
206
+ }
207
+ ```