@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.
- package/dist/docs/core/README.md +84 -0
- package/dist/docs/core/adapters/adapter-architecture.md +262 -0
- package/dist/docs/core/adapters/csr.md +78 -0
- package/dist/docs/core/adapters/custom-adapter.md +357 -0
- package/dist/docs/core/adapters/go-template-adapter.md +269 -0
- package/dist/docs/core/adapters/hono-adapter.md +199 -0
- package/dist/docs/core/adapters.md +37 -0
- package/dist/docs/core/advanced/code-splitting.md +142 -0
- package/dist/docs/core/advanced/compiler-internals.md +331 -0
- package/dist/docs/core/advanced/error-codes.md +261 -0
- package/dist/docs/core/advanced/ir-schema.md +65 -0
- package/dist/docs/core/advanced/performance.md +115 -0
- package/dist/docs/core/advanced/xyflow-browser-bundle.md +69 -0
- package/dist/docs/core/advanced.md +11 -0
- package/dist/docs/core/components/children-slots.md +150 -0
- package/dist/docs/core/components/component-authoring.md +207 -0
- package/dist/docs/core/components/context-api.md +236 -0
- package/dist/docs/core/components/portals.md +192 -0
- package/dist/docs/core/components/props-type-safety.md +97 -0
- package/dist/docs/core/components/styling.md +37 -0
- package/dist/docs/core/components.md +19 -0
- package/dist/docs/core/core-concepts/ai-native.md +83 -0
- package/dist/docs/core/core-concepts/backend-freedom.md +31 -0
- package/dist/docs/core/core-concepts/how-it-works.md +147 -0
- package/dist/docs/core/core-concepts/mpa-style.md +36 -0
- package/dist/docs/core/core-concepts/reactivity.md +35 -0
- package/dist/docs/core/core-concepts.md +28 -0
- package/dist/docs/core/introduction.md +87 -0
- package/dist/docs/core/llms.txt +53 -0
- package/dist/docs/core/quick-start.mdx +160 -0
- package/dist/docs/core/reactivity/create-effect.md +125 -0
- package/dist/docs/core/reactivity/create-memo.md +91 -0
- package/dist/docs/core/reactivity/create-signal.md +128 -0
- package/dist/docs/core/reactivity/on-cleanup.md +67 -0
- package/dist/docs/core/reactivity/on-mount.md +70 -0
- package/dist/docs/core/reactivity/props-reactivity.md +91 -0
- package/dist/docs/core/reactivity/untrack.md +69 -0
- package/dist/docs/core/reactivity.md +28 -0
- package/dist/docs/core/rendering/client-directive.md +82 -0
- package/dist/docs/core/rendering/fragment.md +43 -0
- package/dist/docs/core/rendering/jsx-compatibility.md +163 -0
- package/dist/docs/core/rendering.md +14 -0
- package/dist/index.js +25490 -0
- package/dist/tokens.json +74 -0
- package/package.json +37 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Hono Adapter
|
|
3
|
+
description: Generate Hono JSX templates from the compiler's IR for Hono-based servers.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hono Adapter
|
|
7
|
+
|
|
8
|
+
Generates Hono JSX (`.tsx`) files from the compiler's IR. Works with Hono and any JSX-compatible TypeScript backend.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
npm install @barefootjs/hono
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Basic Usage
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { compile } from '@barefootjs/jsx'
|
|
19
|
+
import { HonoAdapter } from '@barefootjs/hono'
|
|
20
|
+
|
|
21
|
+
const adapter = new HonoAdapter()
|
|
22
|
+
const result = compile(source, { adapter })
|
|
23
|
+
|
|
24
|
+
// result.template → .tsx file content
|
|
25
|
+
// result.clientJs → .client.js file content
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## Options
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
const adapter = new HonoAdapter({
|
|
33
|
+
clientJsBasePath: '/static/components/',
|
|
34
|
+
barefootJsPath: '/static/components/barefoot.js',
|
|
35
|
+
clientJsFilename: 'my-component.client.js',
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Option | Type | Default | Description |
|
|
40
|
+
|--------|------|---------|-------------|
|
|
41
|
+
| `clientJsBasePath` | `string` | `'/static/components/'` | Base path for client JS files |
|
|
42
|
+
| `barefootJsPath` | `string` | `'/static/components/barefoot.js'` | Path to the BarefootJS runtime |
|
|
43
|
+
| `clientJsFilename` | `string` | `'{componentName}.client.js'` | Override the client JS filename |
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Output Format
|
|
47
|
+
|
|
48
|
+
### Server Component
|
|
49
|
+
|
|
50
|
+
Without `"use client"`, the template is generated with props access and hydration markers (for potential parent hydration), but no client JS:
|
|
51
|
+
|
|
52
|
+
**Source:**
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
export function Greeting(props: { name: string }) {
|
|
56
|
+
return <h1>Hello, {props.name}!</h1>
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Output (.tsx):**
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import { bfText, bfTextEnd } from '@barefootjs/hono/utils'
|
|
64
|
+
|
|
65
|
+
export function Greeting(__allProps: { name: string } & { __instanceId?: string; ... }) {
|
|
66
|
+
const { __instanceId, ..., ...props } = __allProps
|
|
67
|
+
const __scopeId = __instanceId || `Greeting_${...}`
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<h1 bf-s={...} bf="s1">
|
|
71
|
+
Hello, {bfText("s0")}{props.name}{bfTextEnd()}!
|
|
72
|
+
</h1>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Client Component
|
|
78
|
+
|
|
79
|
+
**Source:**
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
"use client"
|
|
83
|
+
import { createSignal } from '@barefootjs/client'
|
|
84
|
+
|
|
85
|
+
export function Counter(props: { initial?: number }) {
|
|
86
|
+
const [count, setCount] = createSignal(props.initial ?? 0)
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div>
|
|
90
|
+
<span>Count: {count()}</span>
|
|
91
|
+
<button onClick={() => setCount(n => n + 1)}>+1</button>
|
|
92
|
+
</div>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Output (.tsx):**
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import { bfText, bfTextEnd } from '@barefootjs/hono/utils'
|
|
101
|
+
|
|
102
|
+
export function Counter(__allProps: { initial?: number } & { __instanceId?: string; ... }) {
|
|
103
|
+
const { __instanceId, ..., ...props } = __allProps
|
|
104
|
+
const __scopeId = __instanceId || `Counter_${Math.random().toString(36).slice(2, 8)}`
|
|
105
|
+
const count = () => props.initial ?? 0 // signal → server-side stub
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<div bf-s={...} {...(... ? { "bf-p": __bfPropsJson } : {})}>
|
|
109
|
+
<span bf="s1">Count: {bfText("s0")}{count()}{bfTextEnd()}</span>
|
|
110
|
+
<button onClick={() => {}} bf="s2">+1</button>
|
|
111
|
+
</div>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- `bf-s` — component scope boundary (unique per instance)
|
|
117
|
+
- `bf="sN"` — client JS targets (elements, text nodes)
|
|
118
|
+
- `bfText("s0")` / `bfTextEnd()` — text node markers (rendered as `<!--bf:s0-->...<!--/-->`)
|
|
119
|
+
- Signal stubs (`count = () => props.initial ?? 0`) — render initial values server-side
|
|
120
|
+
- `bf-p` — serialized props JSON for client hydration
|
|
121
|
+
- Event handlers are replaced with no-ops (client JS handles the real ones)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
## Script Collection
|
|
125
|
+
|
|
126
|
+
A build-time post-processing step injects `useRequestContext()` calls into generated templates. `BfScripts` renders the collected `<script>` tags:
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
import { BfScripts } from '@barefootjs/hono'
|
|
130
|
+
|
|
131
|
+
export function Layout({ children }) {
|
|
132
|
+
return (
|
|
133
|
+
<html>
|
|
134
|
+
<body>
|
|
135
|
+
{children}
|
|
136
|
+
<BfScripts />
|
|
137
|
+
</body>
|
|
138
|
+
</html>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Each component's client JS loads once regardless of instance count. See `site/ui/build.ts` for the `addScriptCollection()` pattern.
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
## Hydration Props
|
|
147
|
+
|
|
148
|
+
Every client component's props are extended with hydration fields:
|
|
149
|
+
|
|
150
|
+
| Prop | Purpose |
|
|
151
|
+
|------|---------|
|
|
152
|
+
| `__instanceId` | Unique instance identifier passed from the parent |
|
|
153
|
+
| `__bfScope` | Parent's scope ID (for nested component communication) |
|
|
154
|
+
| `__bfChild` | Marks this component as a child instance (adds `~` prefix to `bf-s` value) |
|
|
155
|
+
| `data-key` | Stable key for list-rendered instances |
|
|
156
|
+
|
|
157
|
+
These are used internally — no manual passing needed.
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
## Conditional Rendering
|
|
161
|
+
|
|
162
|
+
Ternaries with element branches use `bf-c` markers. Text-only ternaries use comment markers:
|
|
163
|
+
|
|
164
|
+
**Element branches:**
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
{loggedIn() ? <span>Welcome back!</span> : <span>Please log in</span>}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
{loggedIn() ? <span bf-c="s0">Welcome back!</span> : <span bf-c="s0">Please log in</span>}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Text-only branches:**
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
{on() ? 'ON' : 'OFF'}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
{on() ? <>{bfComment("cond-start:s0")}{'ON'}{bfComment("cond-end:s0")}</>
|
|
182
|
+
: <>{bfComment("cond-start:s0")}{'OFF'}{bfComment("cond-end:s0")}</>}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Loop Rendering
|
|
186
|
+
|
|
187
|
+
**Source:**
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
{items().map(item => <li key={item}>{item}</li>)}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Output:**
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
{bfComment('loop')}{items().map((item) => <li key={item}>{bfText("s0")}{item}{bfTextEnd()}</li>)}{bfComment('/loop')}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Loop markers (`<!--bf-loop-->...<!--bf-/loop-->`) are used for reconciliation. For child components in loops, the adapter generates unique instance IDs per iteration using the loop index or `key`.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Adapters
|
|
3
|
+
description: Bridge between the compiler's IR and your backend's template language, enabling cross-stack component reuse.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Adapters
|
|
7
|
+
|
|
8
|
+
An adapter converts the compiler's IR into a template your server can render. The same JSX source produces correct output for any adapter.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
JSX Source
|
|
12
|
+
↓
|
|
13
|
+
[Phase 1] → IR (backend-agnostic)
|
|
14
|
+
↓
|
|
15
|
+
[Phase 2a] IR → Adapter → Marked Template (server)
|
|
16
|
+
[Phase 2b] IR → Client JS (browser)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Available Adapters
|
|
20
|
+
|
|
21
|
+
| Adapter | Output | Backend | Package |
|
|
22
|
+
|---------|--------|---------|---------|
|
|
23
|
+
| [`HonoAdapter`](./adapters/hono-adapter.md) | `.tsx` | Hono / JSX-based servers | `@barefootjs/hono` |
|
|
24
|
+
| [`GoTemplateAdapter`](./adapters/go-template-adapter.md) | `.tmpl` + `_types.go` | Go `html/template` | `@barefootjs/go-template` |
|
|
25
|
+
| [CSR](./adapters/csr.md) | — (client-rendered) | None (browser-only) | `@barefootjs/client` |
|
|
26
|
+
|
|
27
|
+
> CSR is not an IR→template adapter. It renders components directly in the browser using client-side template functions — use it when the server can't (or shouldn't) emit the initial HTML.
|
|
28
|
+
|
|
29
|
+
## Pages
|
|
30
|
+
|
|
31
|
+
| Topic | Description |
|
|
32
|
+
|-------|-------------|
|
|
33
|
+
| [Adapter Architecture](./adapters/adapter-architecture.md) | How adapters work, the `TemplateAdapter` interface, and the IR contract |
|
|
34
|
+
| [Hono Adapter](./adapters/hono-adapter.md) | Configuration and output format for Hono / JSX-based servers |
|
|
35
|
+
| [Go Template Adapter](./adapters/go-template-adapter.md) | Configuration and output format for Go `html/template` |
|
|
36
|
+
| [CSR](./adapters/csr.md) | Client-side rendering without a server-rendered template |
|
|
37
|
+
| [Writing a Custom Adapter](./adapters/custom-adapter.md) | Step-by-step guide to implementing your own adapter |
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Vendor code-splitting
|
|
3
|
+
description: Split large vendor libraries into separately-cached browser chunks via barefoot.config.ts externals
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Vendor code-splitting
|
|
7
|
+
|
|
8
|
+
Apps that embed large libraries (xyflow, yjs, etc.) alongside BarefootJS components can reach 700–800 KB of client JS on first visit. Splitting those libraries out as separate browser chunks dramatically cuts repeat-visit transfer:
|
|
9
|
+
|
|
10
|
+
- **Cold visit**: ~36 % smaller because the common vendor bundle is served from disk cache
|
|
11
|
+
- **Warm visit**: ~70 % faster because only the changed component JS hits the network
|
|
12
|
+
|
|
13
|
+
## Configuration
|
|
14
|
+
|
|
15
|
+
Add an `externals` map to `barefoot.config.ts`. The CLI copies each package's browser-ready bundle to your output directory and emits `barefoot-externals.json`.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// barefoot.config.ts
|
|
19
|
+
import { defineConfig } from 'barefootjs/config'
|
|
20
|
+
import { HonoAdapter } from '@barefootjs/hono/adapter'
|
|
21
|
+
|
|
22
|
+
export default defineConfig({
|
|
23
|
+
adapter: HonoAdapter(),
|
|
24
|
+
minify: true,
|
|
25
|
+
externalsBasePath: '/static/components/',
|
|
26
|
+
|
|
27
|
+
externals: {
|
|
28
|
+
// Local chunk — CLI copies the package's umd/unpkg/import entry
|
|
29
|
+
'@barefootjs/xyflow': true,
|
|
30
|
+
|
|
31
|
+
// Preload hint — adds <link rel="modulepreload"> to the importmap manifest
|
|
32
|
+
yjs: { preload: true },
|
|
33
|
+
|
|
34
|
+
// CDN passthrough — no local copy, importmap points at the remote URL
|
|
35
|
+
lodash: { url: 'https://esm.sh/lodash@4.17.21', preload: true },
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### ExternalSpec
|
|
41
|
+
|
|
42
|
+
| Shape | Effect |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `true` | Copy browser-ready entry to `outDir`, auto-resolve via `umd` → `unpkg` → `jsdelivr` → `import` |
|
|
45
|
+
| `{ preload: true }` | Same as `true`, also adds a preload hint to `barefoot-externals.json` |
|
|
46
|
+
| `{ url: string }` | CDN passthrough — skip copy, use URL as-is in importmap |
|
|
47
|
+
| `{ url: string, preload: true }` | CDN passthrough + preload hint |
|
|
48
|
+
|
|
49
|
+
### externalsBasePath
|
|
50
|
+
|
|
51
|
+
URL prefix for vendor chunk entries in the emitted importmap. Defaults to `/<runtimeSubdir>/` (e.g., `/components/` when using the default output layout). Set this explicitly if your static files are served from a different path:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
externalsBasePath: '/static/components/'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## What the CLI emits
|
|
58
|
+
|
|
59
|
+
After build, `dist/barefoot-externals.json` contains three sections:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"importmap": {
|
|
64
|
+
"imports": {
|
|
65
|
+
"@barefootjs/xyflow": "/static/components/xyflow.js",
|
|
66
|
+
"yjs": "/static/components/yjs.js",
|
|
67
|
+
"lodash": "https://esm.sh/lodash@4.17.21",
|
|
68
|
+
"@barefootjs/client": "/static/components/barefoot.js",
|
|
69
|
+
"@barefootjs/client/runtime": "/static/components/barefoot.js",
|
|
70
|
+
"@barefootjs/client/reactive": "/static/components/barefoot.js"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"preloads": [
|
|
74
|
+
"/static/components/yjs.js",
|
|
75
|
+
"https://esm.sh/lodash@4.17.21"
|
|
76
|
+
],
|
|
77
|
+
"externals": [
|
|
78
|
+
"@barefootjs/xyflow",
|
|
79
|
+
"yjs",
|
|
80
|
+
"lodash",
|
|
81
|
+
"@barefootjs/client",
|
|
82
|
+
"@barefootjs/client/runtime",
|
|
83
|
+
"@barefootjs/client/reactive"
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**`@barefootjs/client*` dedup is automatic.** Whenever `externals` is non-empty, the three `@barefootjs/client*` importmap entries are added unconditionally. This prevents reactive-primitive duplication — a class of silent failure where forgetting one entry inlines a second copy of the reactive runtime and breaks signals / context across the module boundary (see #927).
|
|
89
|
+
|
|
90
|
+
## Wiring the importmap into your renderer
|
|
91
|
+
|
|
92
|
+
Read `barefoot-externals.json` at startup and inject it into the HTML shell:
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
// renderer.tsx
|
|
96
|
+
import externalsManifest from './dist/barefoot-externals.json'
|
|
97
|
+
|
|
98
|
+
const importMapScript = JSON.stringify(externalsManifest.importmap)
|
|
99
|
+
|
|
100
|
+
export const renderer = jsxRenderer(({ children }) => (
|
|
101
|
+
<html>
|
|
102
|
+
<head>
|
|
103
|
+
<script type="importmap" dangerouslySetInnerHTML={{ __html: importMapScript }} />
|
|
104
|
+
{externalsManifest.preloads.map(href => (
|
|
105
|
+
<link rel="modulepreload" href={href} />
|
|
106
|
+
))}
|
|
107
|
+
</head>
|
|
108
|
+
<body>
|
|
109
|
+
{children}
|
|
110
|
+
<BfScripts />
|
|
111
|
+
</body>
|
|
112
|
+
</html>
|
|
113
|
+
))
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Using the externals list in your own bun build
|
|
117
|
+
|
|
118
|
+
The `externals` array in `barefoot-externals.json` lists every package that the browser will load via the importmap. Pass these as `--external` flags when bundling your app entries:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
# Shell — build your DeskCanvas.tsx with all externals applied
|
|
122
|
+
EXTERNALS=$(jq -r '.externals[]' dist/barefoot-externals.json | sed 's/^/--external /' | tr '\n' ' ')
|
|
123
|
+
bun build worker/components/canvas/DeskCanvas.tsx \
|
|
124
|
+
--outfile dist/static/components/canvas.js \
|
|
125
|
+
--format esm --minify \
|
|
126
|
+
$EXTERNALS
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Or in JavaScript:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import manifest from './dist/barefoot-externals.json'
|
|
133
|
+
|
|
134
|
+
await Bun.build({
|
|
135
|
+
entrypoints: ['./worker/components/canvas/DeskCanvas.tsx'],
|
|
136
|
+
outdir: './dist/static/components',
|
|
137
|
+
naming: 'canvas.[ext]',
|
|
138
|
+
format: 'esm',
|
|
139
|
+
minify: true,
|
|
140
|
+
external: manifest.externals,
|
|
141
|
+
})
|
|
142
|
+
```
|