@barefootjs/vite 0.30.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 (61) hide show
  1. package/dist/child-marker.d.ts +62 -0
  2. package/dist/child-marker.d.ts.map +1 -0
  3. package/dist/compile-cache.d.ts +19 -0
  4. package/dist/compile-cache.d.ts.map +1 -0
  5. package/dist/component-manifest.d.ts +69 -0
  6. package/dist/component-manifest.d.ts.map +1 -0
  7. package/dist/corpus-program.d.ts +41 -0
  8. package/dist/corpus-program.d.ts.map +1 -0
  9. package/dist/debounced-serial-runner.d.ts +27 -0
  10. package/dist/debounced-serial-runner.d.ts.map +1 -0
  11. package/dist/dev-server.d.ts +99 -0
  12. package/dist/dev-server.d.ts.map +1 -0
  13. package/dist/discover.d.ts +117 -0
  14. package/dist/discover.d.ts.map +1 -0
  15. package/dist/emit.d.ts +9 -0
  16. package/dist/emit.d.ts.map +1 -0
  17. package/dist/index.d.ts +8 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +24626 -0
  20. package/dist/manifest.d.ts +39 -0
  21. package/dist/manifest.d.ts.map +1 -0
  22. package/dist/paths.d.ts +57 -0
  23. package/dist/paths.d.ts.map +1 -0
  24. package/dist/plugin.d.ts +5 -0
  25. package/dist/plugin.d.ts.map +1 -0
  26. package/dist/resolve-client-js.d.ts +6 -0
  27. package/dist/resolve-client-js.d.ts.map +1 -0
  28. package/dist/types.d.ts +141 -0
  29. package/dist/types.d.ts.map +1 -0
  30. package/package.json +55 -0
  31. package/src/__tests__/child-marker.test.ts +24 -0
  32. package/src/__tests__/compile-cache.test.ts +73 -0
  33. package/src/__tests__/component-dir-entry.test.ts +239 -0
  34. package/src/__tests__/component-manifest.test.ts +124 -0
  35. package/src/__tests__/corpus-program.test.ts +244 -0
  36. package/src/__tests__/debounced-serial-runner.test.ts +131 -0
  37. package/src/__tests__/dev-server.test.ts +138 -0
  38. package/src/__tests__/discover.test.ts +148 -0
  39. package/src/__tests__/e2e-vite-build.test.ts +191 -0
  40. package/src/__tests__/e2e-vite-dev.test.ts +478 -0
  41. package/src/__tests__/emit.test.ts +73 -0
  42. package/src/__tests__/manifest.test.ts +146 -0
  43. package/src/__tests__/paths.test.ts +93 -0
  44. package/src/__tests__/plugin.test.ts +417 -0
  45. package/src/__tests__/relative-import-rewrite.test.ts +79 -0
  46. package/src/__tests__/resolve-client-js.test.ts +55 -0
  47. package/src/__tests__/templates-optional.test.ts +139 -0
  48. package/src/child-marker.ts +67 -0
  49. package/src/compile-cache.ts +63 -0
  50. package/src/component-manifest.ts +139 -0
  51. package/src/corpus-program.ts +125 -0
  52. package/src/debounced-serial-runner.ts +67 -0
  53. package/src/dev-server.ts +184 -0
  54. package/src/discover.ts +230 -0
  55. package/src/emit.ts +66 -0
  56. package/src/index.ts +25 -0
  57. package/src/manifest.ts +89 -0
  58. package/src/paths.ts +114 -0
  59. package/src/plugin.ts +792 -0
  60. package/src/resolve-client-js.ts +34 -0
  61. package/src/types.ts +144 -0
@@ -0,0 +1,62 @@
1
+ /**
2
+ * `@bf-child:<Name>` marker resolution.
3
+ *
4
+ * The compiler emits `import '/* @bf-child:ChildName *\/'` inside a
5
+ * component's client JS for every OTHER component it references (loop-body
6
+ * children, `initChild`-driven nested components, etc.) — see
7
+ * `packages/jsx/src/ir-to-client-js/child-components.ts`. That specifier
8
+ * is not a real module: it's a marker this plugin must resolve at build
9
+ * time, one way or another, for every reference it stands for.
10
+ *
11
+ * Simply DROPPING the marker (resolving it to an empty no-op module) is
12
+ * not a safe choice for every child reference the marker stands for, only
13
+ * for SOME of them. The distinction (found empirically against gin's real
14
+ * TodoApp/TodoItem — no PR01-03 fixture exercised this shape):
15
+ *
16
+ * - A child rendered via `initChild()` (an SSR-hydrated child, or one
17
+ * whose scope a cross-template Go/ERB/… render already put on the
18
+ * page) is genuinely safe to drop: `@barefootjs/client`'s registry
19
+ * (`packages/client/src/runtime/registry.ts`) queues an `initChild`
20
+ * call for a not-yet-registered name (`pendingChildInits`) and drains
21
+ * it the moment the child's OWN script loads and calls
22
+ * `registerComponent` — however that script physically reached the
23
+ * page. As long as the child's own template renders somewhere (which
24
+ * is what registers its script — see `plugin.ts`'s docstring), this
25
+ * is load-order-tolerant by design.
26
+ * - A child created via `createComponent(name, …)` for a PURELY
27
+ * client-rendered loop (no server-side row template at all — e.g.
28
+ * TodoApp's `.map()` over `initialTodos`, as opposed to TodoAppSSR's
29
+ * server-rendered rows) is NOT tolerant: `materializeComponent`
30
+ * (`packages/client/src/runtime/component.ts`) does one synchronous
31
+ * `getTemplate(name)` registry lookup with NO queueing — if the
32
+ * child's script hasn't run yet, it silently renders a placeholder
33
+ * and NEVER retries. If nothing else on the page happens to reference
34
+ * the child, ITS SCRIPT NEVER LOADS AT ALL, and the row permanently
35
+ * fails to render.
36
+ *
37
+ * Resolving every marker to a REAL import of the named child's `.tsx`
38
+ * source (when discovered) closes this gap the same way Rollup already
39
+ * handles every other cross-module reference in this design: the
40
+ * bare `import '/* @bf-child:ChildName *\/'` statement's TEXT doesn't
41
+ * need to change, only what it resolves to. Once it resolves to
42
+ * `ChildName.tsx`, Rollup's OWN module graph puts an entry-to-entry
43
+ * static import in the output (the child is ALSO independently an entry
44
+ * point — every discovered `'use client'` file is), which is exactly
45
+ * what makes the browser fetch and execute the child's script as a side
46
+ * effect of loading the parent's — no registry timing dependent on
47
+ * anything server-side at all. A name that can't be resolved (unknown,
48
+ * or a multi-component-per-file export the simple name→file map below
49
+ * doesn't cover) falls back to the empty no-op module rather than
50
+ * failing the build outright — the SAME degraded-but-shippable behavior
51
+ * as before this fix for whatever slice of cases it doesn't cover,
52
+ * rather than a regression for OTHER apps that build cleanly today.
53
+ */
54
+ /** The single virtual module id an UNRESOLVED `@bf-child:` marker falls
55
+ * back to — one shared id (not one per child name) because the module's
56
+ * content is always the same (empty) and Rollup dedupes same-id imports
57
+ * for free. */
58
+ export declare const BF_CHILD_NOOP_ID = "\0barefoot-bf-child-noop";
59
+ /** The child component name embedded in a `@bf-child:` marker, or `null`
60
+ * if `source` doesn't look like a compiler-emitted one. */
61
+ export declare function bfChildMarkerName(source: string): string | null;
62
+ //# sourceMappingURL=child-marker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-marker.d.ts","sourceRoot":"","sources":["../src/child-marker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAIH;;;eAGe;AACf,eAAO,MAAM,gBAAgB,6BAA6B,CAAA;AAE1D;2DAC2D;AAC3D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE/D"}
@@ -0,0 +1,19 @@
1
+ import type { CompileResult } from '@barefootjs/jsx';
2
+ export declare class CompileCache {
3
+ private rows;
4
+ /**
5
+ * Return the cached `CompileResult` for `absPath` if its content hash
6
+ * matches what's cached; otherwise call `compile()`, cache the result,
7
+ * and return it. `compile()` runs at most once per distinct
8
+ * `(absPath, content)` pair.
9
+ */
10
+ getOrCompile(absPath: string, content: string, compile: () => CompileResult): CompileResult;
11
+ /** Look up a previously cached result without recompiling. */
12
+ peek(absPath: string): CompileResult | undefined;
13
+ /** Drop a single file's cached entry — used when a file is deleted
14
+ * (dev watcher `'unlink'`) so a later file recreated at the same path
15
+ * never reuses a stale result keyed only by path, not content. */
16
+ delete(absPath: string): void;
17
+ clear(): void;
18
+ }
19
+ //# sourceMappingURL=compile-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-cache.d.ts","sourceRoot":"","sources":["../src/compile-cache.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAWpD,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAA8B;IAE1C;;;;;OAKG;IACH,YAAY,CACV,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,aAAa,GAC3B,aAAa,CAQf;IAED,8DAA8D;IAC9D,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAE/C;IAED;;sEAEkE;IAClE,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE5B;IAED,KAAK,IAAI,IAAI,CAEZ;CACF"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Reassembles ONE source file's row for the combined `manifest.json` this
3
+ * plugin writes to `templatesDir` alongside the per-component
4
+ * `<Name>.ssr-defaults.json` files `emit.ts`'s `planEmits` already produces.
5
+ *
6
+ * WHY THIS EXISTS (not just the per-component files): every PHP/Python/Ruby
7
+ * backend driving a `templatesPerComponent` adapter (Blade/Jinja2/ERB) reads
8
+ * `ssrDefaults` — an optional-prop-derived signal's SSR seed value — from
9
+ * disk at REQUEST time (there is no compile step to bake it into source the
10
+ * way Go's generated `NewXxxProps` constructor or Hono's self-contained
11
+ * `.tsx` file can). Combining every source file's row into one manifest
12
+ * means each backend reads a single file instead of glob-and-reassembling
13
+ * the identical `{ [component]: { ssrDefaults } }` shape itself — avoiding
14
+ * seven copies of the same reconstruction logic across three languages,
15
+ * each of which could drift or break independently. One place in core
16
+ * beats three `/vite` packages reimplementing it, and
17
+ * `@barefootjs/go-template/vite` / `@barefootjs/hono/vite` get the same
18
+ * manifest for free even though neither adapter's own backend currently
19
+ * reads it (Go bakes `ssrDefaults` into generated source; Hono's `.tsx`
20
+ * inlines them as JS defaults) — see this module's own callers for the
21
+ * confirmation that neither reads a manifest today.
22
+ *
23
+ * Implemented standalone rather than by importing from `@barefootjs/cli`,
24
+ * for the same reason as `paths.ts`'s header comment: that package's only
25
+ * published entry point is the full `bf` binary.
26
+ *
27
+ * Two fields are deliberately NOT part of `ManifestEntry`:
28
+ *
29
+ * - `stubDeps` is not emitted: Rollup's own module graph resolution
30
+ * handles dependency wiring, so there is no separate stub-dependency
31
+ * bookkeeping to produce, and no consumer reads such a field.
32
+ * - `clientJs` is not emitted: there is no single static path to put
33
+ * there. The real client JS URL is content-hashed and mode-dependent
34
+ * (dev-origin vs. build-manifest-resolved) — exactly what
35
+ * `scriptAssets` already resolves and bakes directly into the compiled
36
+ * template's own script-registration call. No adapter backend or native
37
+ * runtime reads `manifest[name].clientJs`; however, `@barefootjs/hono`'s
38
+ * `BfPreload` component can read `clientJs` from a caller-supplied
39
+ * manifest object (legacy site builds emit one). Plugin-manifest
40
+ * consumers wanting preloads use the `preloadAssets` path instead
41
+ * (`registerComponentPreloads` → `<link rel="modulepreload">`).
42
+ */
43
+ import type { CompileResult, TemplateAdapter } from '@barefootjs/jsx';
44
+ /** One exported component's row inside a multi-export source file's
45
+ * `components` map (`templatesPerComponent` adapters only). */
46
+ export interface ManifestComponentEntry {
47
+ markedTemplate: string;
48
+ ssrDefaults?: Record<string, unknown>;
49
+ }
50
+ /** One SOURCE FILE's row in the combined manifest (see this module's
51
+ * header for the fields intentionally not included). */
52
+ export interface ManifestEntry {
53
+ markedTemplate: string;
54
+ ssrDefaults?: Record<string, unknown>;
55
+ /** Per-exported-component rows for `templatesPerComponent` adapters
56
+ * (piconic-ai/barefootjs#2132) — present even for a single-component
57
+ * file. */
58
+ components?: Record<string, ManifestComponentEntry>;
59
+ }
60
+ /**
61
+ * Builds one source file's `{ manifestKey, entry }` pair from its
62
+ * already-compiled `CompileResult`. Returns `null` when the compile
63
+ * produced no `markedTemplate` at all (nothing to register).
64
+ */
65
+ export declare function buildManifestEntry(result: CompileResult, absPath: string, componentDirs: readonly string[], adapter: TemplateAdapter): {
66
+ manifestKey: string;
67
+ entry: ManifestEntry;
68
+ } | null;
69
+ //# sourceMappingURL=component-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-manifest.d.ts","sourceRoot":"","sources":["../src/component-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGrE;+DAC+D;AAC/D,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACtC;AAED;wDACwD;AACxD,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC;;eAEW;IACX,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAA;CACpD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,OAAO,EAAE,eAAe,GACvB;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAiEtD"}
@@ -0,0 +1,41 @@
1
+ import type ts from 'typescript';
2
+ export declare class CorpusProgramManager {
3
+ private program;
4
+ private roots;
5
+ /**
6
+ * (Re)build the corpus Program from a full discovery pass's snapshot.
7
+ * Filters `files` down to the ones needing type-based detection; no-ops
8
+ * entirely (keeping the existing Program) when the root set and every
9
+ * root's on-Program text are unchanged — the common case for the dev
10
+ * watcher's full re-runs, where `CompileCache` already makes unchanged
11
+ * files free and this keeps the Program free too.
12
+ *
13
+ * Callers pass the content DISCOVERY read, and `createProgramForCorpus`'s
14
+ * host re-reads from disk — the two can only diverge if the file changed
15
+ * in the microseconds between, and `programFor`'s per-file text check
16
+ * catches exactly that before any compile trusts the Program.
17
+ */
18
+ seed(files: readonly {
19
+ absPath: string;
20
+ content: string;
21
+ }[]): void;
22
+ /**
23
+ * The Program to pass as `CompileOptions.program` when compiling
24
+ * `absPath` with `content` — or `undefined` when the file doesn't need
25
+ * type-based detection at all (the analyzer then never builds a checker,
26
+ * and passing nothing costs nothing).
27
+ *
28
+ * Handles the two ways the seeded Program can be behind reality:
29
+ * - `absPath` isn't a root yet (a needing file created after the last
30
+ * seed, reached by the graph pass before the next eager pass) or its
31
+ * disk content changed: add the root and rebuild incrementally.
32
+ * - `content` diverges from what's on disk even after a rebuild (an
33
+ * in-flight edit): fall back to a virtual single-file Program built
34
+ * from `content` itself — the pre-manager per-file behavior, correct
35
+ * and BF050-suppressing, just slow, and only for that one file until
36
+ * disk catches up.
37
+ */
38
+ programFor(absPath: string, content: string): ts.Program | undefined;
39
+ private rebuild;
40
+ }
41
+ //# sourceMappingURL=corpus-program.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"corpus-program.d.ts","sourceRoot":"","sources":["../src/corpus-program.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAA;AAOhC,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,KAAK,CAAoB;IAEjC;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,KAAK,EAAE,SAAS;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,IAAI,CAqBjE;IAED;;;;;;;;;;;;;;;OAeG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC,OAAO,GAAG,SAAS,CAcnE;IAED,OAAO,CAAC,OAAO;CAYhB"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Debounce + serialize an async task behind a single `trigger()` entry
3
+ * point. Built for `configureServer`'s watcher handlers: a burst of
4
+ * `'change'`/`'add'`/`'unlink'` events (save-twice-quickly, a multi-file
5
+ * save, a `git checkout` touching many files) must not start several
6
+ * overlapping eager passes writing the same template files.
7
+ *
8
+ * Two, deliberately separate, guarantees:
9
+ * - **debounce**: `trigger()` calls within `debounceMs` of each other
10
+ * collapse into a single scheduled run.
11
+ * - **serialize + coalesce**: if `task()` is still running when the
12
+ * debounce timer fires, this does NOT start a second, overlapping
13
+ * call — it marks exactly one follow-up run, which starts the instant
14
+ * the in-flight one finishes. A change arriving mid-pass is delayed,
15
+ * never dropped, and at most one run is ever in flight.
16
+ *
17
+ * Deliberately minimal: no queue of distinct payloads, no rehashing —
18
+ * `task()` itself (the caller's full eager pass) is the unit of work, and
19
+ * it re-discovers everything from disk on every call, so "run it again"
20
+ * is always correct regardless of how many trigger()s piled up.
21
+ */
22
+ export interface DebouncedSerialRunner {
23
+ /** Schedule a run, debounced. Safe to call from multiple event sources. */
24
+ trigger(): void;
25
+ }
26
+ export declare function createDebouncedSerialRunner(task: () => Promise<void>, debounceMs: number, onError: (err: unknown) => void): DebouncedSerialRunner;
27
+ //# sourceMappingURL=debounced-serial-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounced-serial-runner.d.ts","sourceRoot":"","sources":["../src/debounced-serial-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EACzB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAC9B,qBAAqB,CAoCvB"}
@@ -0,0 +1,99 @@
1
+ import type { ResolvedConfig, ViteDevServer } from 'vite';
2
+ /**
3
+ * Localhost-only CORS default this plugin fills in — ONLY when the user
4
+ * hasn't configured `server.cors` themselves (see the `config` hook in
5
+ * `plugin.ts`). Vite 6+ defaults `cors` to same-origin-only, which breaks
6
+ * the cross-origin split this plugin sets up (the page is rendered by the
7
+ * backend on its own origin; modules are served by Vite on another)
8
+ * unless something opts localhost origins in. Deliberately not a wildcard
9
+ * `true` — see the PR brief for the reasoning.
10
+ */
11
+ export declare const DEFAULT_DEV_CORS_ORIGIN: RegExp;
12
+ /**
13
+ * Debounce window (ms) for the dev watcher's `'change'` / `'add'` /
14
+ * `'unlink'` handlers — long enough to coalesce a save-twice-quickly or a
15
+ * multi-file save/`git checkout` into a single eager pass, short enough
16
+ * that a reload still feels instant.
17
+ */
18
+ export declare const DEV_WATCH_DEBOUNCE_MS = 100;
19
+ /**
20
+ * The request path (relative to `config.base`, no leading slash) a browser
21
+ * must use to reach `absPath` through Vite's dev server: a root-relative
22
+ * path when `absPath` is under `config.root`, or Vite's `/@fs/`
23
+ * absolute-path passthrough when it isn't.
24
+ */
25
+ export declare function devRequestPath(config: Pick<ResolvedConfig, 'root'>, absPath: string): string;
26
+ /** Full absolute URL (origin + `base` + request path) for `absPath` under
27
+ * the dev server. */
28
+ export declare function devModuleUrl(config: Pick<ResolvedConfig, 'root' | 'base'>, origin: string, absPath: string): string;
29
+ /**
30
+ * The ordered `scriptAssets` a `'use client'` component needs in dev: the
31
+ * `@vite/client` HMR/full-reload socket first (so the page always gets a
32
+ * live-reload connection), then the component's own module — Vite serves
33
+ * it plain-JS via this plugin's `transform` hook exactly like it would any
34
+ * other dev module, no different from a production entry. Per the design,
35
+ * server-only components (no `'use client'`) get `[]` — computed by the
36
+ * caller without consulting this function at all, see `plugin.ts`.
37
+ */
38
+ export declare function devScriptAssets(config: Pick<ResolvedConfig, 'root' | 'base'>, origin: string, absPath: string): string[];
39
+ /**
40
+ * The dev origin to bake into `scriptAssets`: the user's own
41
+ * `server.origin` if they set one, otherwise `http://localhost:<port>`
42
+ * using the port Vite actually bound — NOT the configured port, which can
43
+ * be wrong (Vite auto-increments past an in-use port unless `strictPort`
44
+ * is set). Also writes the computed default back onto
45
+ * `server.config.server.origin` so Vite's OWN asset-URL rewriting
46
+ * (`import.meta.url`, CSS `url()`, etc.) agrees with the URLs this plugin
47
+ * bakes into templates — both need to match for the cross-origin split
48
+ * (page from the backend, assets from Vite) to work end to end.
49
+ *
50
+ * Call only after the server is actually listening (`httpServer`'s
51
+ * `'listening'` event) — the resolved port isn't known before then.
52
+ */
53
+ export declare function resolveDevOrigin(server: ViteDevServer): string;
54
+ /**
55
+ * Filename of the marker BarefootJS writes at the root of `templates`
56
+ * while the dev server is running, so a stray `git add` or a production
57
+ * deploy of dev-only output (localhost URLs baked into every template) is
58
+ * obvious before it ships. `writeBundle` (the `vite build` path) removes
59
+ * it — see `plugin.ts`.
60
+ *
61
+ * A per-template, per-adapter comment (Go `{{/* … *\/}}`, ERB `<%# … %>`,
62
+ * etc.) would pinpoint the problem more precisely, but needs new surface
63
+ * on every `TemplateAdapter` implementation across 9+ adapter packages —
64
+ * out of scope for a dev-server PR that touches none of them. The brief
65
+ * explicitly allows this single-file fallback in that case.
66
+ */
67
+ export declare const DEV_ARTIFACT_MARKER_FILENAME = ".barefootjs-dev-build";
68
+ export declare const DEV_ARTIFACT_MARKER_CONTENT = "This directory currently holds DEV BUILD OUTPUT from @barefootjs/vite's\ndev server, not a production build.\n\nEvery template in this directory has dev-only URLs baked into it\n(http://localhost:<port>/...) pointing at the Vite dev server. They will\nbreak if committed, deployed, or served without that dev server running.\n\nRun `vite build` to regenerate this directory with real, hashed,\nproduction asset URLs \u2014 the build overwrites every template here and\nremoves this file.\n";
69
+ /**
70
+ * Cross-language dev-reload sentinel: `<outDir>/.dev/build-id`, ONE
71
+ * DIRECTORY ABOVE `templates`. The path is fixed, not derived from
72
+ * `templatesDir`, because several server runtimes below poll this exact
73
+ * location.
74
+ *
75
+ * Several adapter runtimes poll this exact path for a value change and
76
+ * push an SSE `event: reload` on it — a mechanism that does NOT require
77
+ * the polling process to restart, only the file's mtime/content to
78
+ * change: `bfdev.NewReloadHandler` (Go — echo/gin/chi/nethttp),
79
+ * `Mojolicious::Plugin::BarefootJS::DevReload` /
80
+ * `BarefootJS::DevReload` (Perl — mojolicious/xslate), and
81
+ * `barefoot_js/dev_reload.rb` (Ruby — sinatra/rails, ERB). `vite dev` is
82
+ * the only piece of the dev loop those adapters' apps run alongside — if
83
+ * this plugin didn't write the sentinel, nothing would, and their reload
84
+ * handlers would never fire.
85
+ *
86
+ * Hono's dev-reload story does not consume this at all: both its
87
+ * Cloudflare Workers target (`dev-worker.ts`'s boot id) and its Node
88
+ * target (`barefootDevReload`'s SSE endpoint, wired up in the scaffold's
89
+ * `factory.ts`) detect a restart directly over their own SSE connection,
90
+ * no file involved. Writing this sentinel unconditionally whenever
91
+ * `templates` is configured is harmless there — nothing reads it — which
92
+ * is what keeps this a zero-config, adapter-agnostic signal rather than a
93
+ * 4th plugin option naming which adapters want it.
94
+ */
95
+ export declare const DEV_SENTINEL_SUBDIR = ".dev";
96
+ export declare const DEV_SENTINEL_FILENAME = "build-id";
97
+ /** Absolute path of the dev-reload sentinel for a given `templates` dir. */
98
+ export declare function devSentinelPath(templatesDir: string): string;
99
+ //# sourceMappingURL=dev-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAczD;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,QAAiD,CAAA;AAErF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,MAAM,CAAA;AAQxC;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAM5F;AAED;qBACqB;AACrB,wBAAgB,YAAY,CAC1B,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC,EAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC,EAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,MAAM,EAAE,CAKV;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAS9D;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,4BAA4B,0BAA0B,CAAA;AAEnE,eAAO,MAAM,2BAA2B,8eAUvC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,mBAAmB,SAAS,CAAA;AACzC,eAAO,MAAM,qBAAqB,aAAa,CAAA;AAE/C,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE5D"}
@@ -0,0 +1,117 @@
1
+ /** Does `content` start with a `'use client'` / `"use client"` directive
2
+ * (after skipping leading block/line comments)? */
3
+ export declare function hasUseClientDirective(content: string): boolean;
4
+ /**
5
+ * Is `name` (a bare filename, not a path) a component source file this
6
+ * plugin should discover/compile? `.tsx`, excluding `.test.tsx`,
7
+ * `.spec.tsx`, and `.preview.tsx`. Exported separately from
8
+ * `discoverComponentFiles` so the dev-server file watcher (`plugin.ts`'s
9
+ * `configureServer`) can apply the exact same filter to a single changed
10
+ * path without re-walking a directory.
11
+ */
12
+ export declare function isComponentSourceFile(name: string): boolean;
13
+ /**
14
+ * Recursively discover `.tsx` component files in a directory.
15
+ * Skips `.test.tsx`, `.spec.tsx`, and `.preview.tsx` files.
16
+ */
17
+ export declare function discoverComponentFiles(dir: string, options?: {
18
+ skipDirs?: string[];
19
+ }): Promise<string[]>;
20
+ export interface DiscoveredComponent {
21
+ /** Absolute path to the `.tsx` source file. */
22
+ absPath: string;
23
+ /**
24
+ * The file's full source text, as read by the discovery pass. Retained
25
+ * (discovery had to read it anyway for the directive/exports checks) so
26
+ * downstream consumers — the corpus-program seeding and the eager pass's
27
+ * compile loop — work from the SAME snapshot discovery classified,
28
+ * instead of re-reading and racing an edit that landed in between.
29
+ */
30
+ content: string;
31
+ /** Whether the file's content starts with a `'use client'` directive. */
32
+ isClient: boolean;
33
+ /**
34
+ * Every component this file exports, from `@barefootjs/jsx`'s TS-AST
35
+ * walk (`listExportedComponents`) — never a regex, and never the
36
+ * basename standing in for the name. A file exporting more than one
37
+ * component (`icon/index.tsx` → `CopyIcon` + `CheckIcon`) is why this
38
+ * exists; see `buildChildNameIndex`.
39
+ */
40
+ exportedComponents: string[];
41
+ /**
42
+ * `CompileOptions.cssLayerPrefix` this file should compile with, carried
43
+ * over unchanged from whichever `components` entry's `dir` this file was
44
+ * discovered under (see `ResolvedComponentDirEntry.cssLayerPrefix`).
45
+ * `undefined` when that entry set none (or was a plain string entry).
46
+ */
47
+ cssLayerPrefix?: string;
48
+ }
49
+ /**
50
+ * A `components` directory to scan, already resolved to an absolute `dir`,
51
+ * plus the per-directory compile behavior `barefoot()`'s `ComponentDirEntry`
52
+ * (`types.ts`) carries. `discoverComponents` also accepts a plain absolute
53
+ * path string as shorthand for `{ dir: string }` — the same "string is
54
+ * exactly equivalent to `{ dir }`" equivalence `ComponentDirEntry` itself
55
+ * documents — so existing callers that only ever had bare directories
56
+ * (`integrations/h3`/`elysia`'s `vite.config.ts`, reusing this exported
57
+ * function to resolve every discovered client component's URL) keep
58
+ * compiling and behaving unchanged.
59
+ */
60
+ export interface ResolvedComponentDirEntry {
61
+ /** Absolute path to the source directory to scan. */
62
+ dir: string;
63
+ /** Stamped onto every `DiscoveredComponent` found under `dir` — see
64
+ * `DiscoveredComponent.cssLayerPrefix`. */
65
+ cssLayerPrefix?: string;
66
+ /** Directory NAMES to skip anywhere under `dir` — passed straight
67
+ * through to `discoverComponentFiles`. */
68
+ skipDirs?: string[];
69
+ }
70
+ /**
71
+ * Scan every configured `components` directory for `.tsx` files and
72
+ * classify each as client (`'use client'`) or server-only. Each entry may
73
+ * be a plain absolute path (shorthand for `{ dir }`, no `cssLayerPrefix`/
74
+ * `skipDirs`) or a `ResolvedComponentDirEntry`.
75
+ *
76
+ * A file reachable under more than one entry is discovered once, stamped
77
+ * with the FIRST matching entry's `cssLayerPrefix` — entries are walked in
78
+ * array order and `seen` short-circuits every later match, the same
79
+ * first-writer-wins precedence `buildChildNameIndex` already documents for
80
+ * `@bf-child:` name collisions.
81
+ */
82
+ export declare function discoverComponents(entries: readonly (string | ResolvedComponentDirEntry)[], readFile: (absPath: string) => Promise<string>): Promise<DiscoveredComponent[]>;
83
+ /**
84
+ * Component-name → absolute-path index used to resolve `@bf-child:<Name>`
85
+ * markers (see `child-marker.ts`) to a real file: a bare-marker child
86
+ * reference embeds only the referenced component's NAME (the compiler has
87
+ * no filesystem access at that phase — see `child-components.ts`), so
88
+ * `resolveId` needs a name→file lookup built from a full discovery pass.
89
+ *
90
+ * Keyed by each exported component NAME, which is what the marker
91
+ * carries. Server-only files are excluded: a `@bf-child:` marker only
92
+ * ever names another component this one instantiates at runtime
93
+ * (`initChild`/`createComponent`), which requires an `init` function only
94
+ * a `'use client'` file has.
95
+ *
96
+ * This used to key on the file's basename, which worked only because the
97
+ * one-component-per-file convention makes the two coincide
98
+ * (`TodoItem.tsx` exports `TodoItem`). A file exporting several
99
+ * components broke it silently: `icon/index.tsx` was keyed `index`, so
100
+ * `@bf-child:CopyIcon` found nothing and fell through to the no-op module
101
+ * (`plugin.ts`'s `resolveId`) — a child that never hydrates, with no
102
+ * diagnostic.
103
+ *
104
+ * The blast radius was wider than multi-export files. Because the key was
105
+ * the bare basename, EVERY colocated `index.tsx` collided on the single
106
+ * key `"index"` — including single-export ones like `ui/button/index.tsx`
107
+ * exporting `Button`. No colocated component was reachable as a
108
+ * `@bf-child:` target at all, whatever its export count. Measured with
109
+ * `listExportedComponents` over `ui/components` + `site/ui/components`:
110
+ * 112 files export more than one component, 105 of them `'use client'`.
111
+ *
112
+ * First writer wins on a duplicate name, and discovery order is the
113
+ * `components` option's order — so an earlier directory shadows a later
114
+ * one, the same precedence the option list already implies.
115
+ */
116
+ export declare function buildChildNameIndex(discovered: readonly Pick<DiscoveredComponent, 'absPath' | 'isClient' | 'exportedComponents'>[]): Map<string, string>;
117
+ //# sourceMappingURL=discover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAeA;mDACmD;AACnD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAe9D;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAO3D;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAChC,OAAO,CAAC,MAAM,EAAE,CAAC,CAwBnB;AAED,MAAM,WAAW,mBAAmB;IAClC,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAA;IACf;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAA;IACjB;;;;;;OAMG;IACH,kBAAkB,EAAE,MAAM,EAAE,CAAA;IAC5B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,yBAAyB;IACxC,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAA;IACX;+CAC2C;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;8CAC0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,SAAS,CAAC,MAAM,GAAG,yBAAyB,CAAC,EAAE,EACxD,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAC7C,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAuBhC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,mBAAmB,CAIjC,UAAU,EAAE,SAAS,IAAI,CAAC,mBAAmB,EAAE,SAAS,GAAG,UAAU,GAAG,oBAAoB,CAAC,EAAE,GAC9F,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAerB"}
package/dist/emit.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { CompileResult, TemplateAdapter } from '@barefootjs/jsx';
2
+ export interface EmitTarget {
3
+ /** POSIX path, relative to the `templates` dir. */
4
+ relPath: string;
5
+ content: string;
6
+ }
7
+ export declare function planEmits(result: CompileResult, absPath: string, componentDirs: readonly string[], adapter: TemplateAdapter): EmitTarget[];
8
+ export declare function writeEmits(templatesDir: string, targets: EmitTarget[]): Promise<void>;
9
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGrE,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,SAAS,CACvB,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,OAAO,EAAE,eAAe,GACvB,UAAU,EAAE,CAuBd;AAED,wBAAsB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAM3F"}
@@ -0,0 +1,8 @@
1
+ export { barefoot, PLUGIN_NAME } from './plugin.ts';
2
+ export { barefoot as default } from './plugin.ts';
3
+ export type { AfterEmitContext, BarefootPluginApi, BarefootViteOptions, ComponentDirEntry } from './types.ts';
4
+ export { loadManifest, resolveScriptAssets, joinBaseAndFile } from './manifest.ts';
5
+ export { devModuleUrl, devRequestPath, resolveDevOrigin } from './dev-server.ts';
6
+ export { toPosixRelative } from './paths.ts';
7
+ export { discoverComponents, type DiscoveredComponent, type ResolvedComponentDirEntry } from './discover.ts';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,QAAQ,IAAI,OAAO,EAAE,MAAM,aAAa,CAAA;AACjD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAO7G,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAClF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAa5C,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,KAAK,yBAAyB,EAAE,MAAM,eAAe,CAAA"}