@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,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
+ ```