@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,34 @@
1
+ /**
2
+ * `resolveId` shim: maps the compiler's synthesized `./foo.client.js`
3
+ * sibling-import specifier back to the real `./foo.tsx` source file on
4
+ * disk. There is no `.client.js` file for Vite to find — the compiler only
5
+ * ever read `foo.tsx`.
6
+ *
7
+ * Scope, per the spike (spike-findings.md, R2): the `.client.js` rewrite
8
+ * (`packages/jsx/src/ir-to-client-js/imports.ts:177`, gated by
9
+ * `analyzer.ts`'s `scanImportedClientSignals`) only ever fires for
10
+ * **relative** specifiers (`./`, `../`) that import a module exporting
11
+ * client signals — alias imports (`@/components/foo`) are never rewritten
12
+ * by the compiler, so they reach Vite as plain bare specifiers that
13
+ * `resolve.alias` already resolves natively (proven in the spike: both
14
+ * resolution paths converge on the same module id and Rollup dedupes them
15
+ * into one shared chunk). Do NOT add alias handling here.
16
+ */
17
+ import { existsSync } from 'node:fs'
18
+ import { dirname, resolve } from 'node:path'
19
+
20
+ const CLIENT_JS_SUFFIX = '.client.js'
21
+
22
+ /**
23
+ * Resolve `source` (an import specifier seen by Vite's `resolveId`) to the
24
+ * real `.tsx` file it stands in for, or `null` if this shim doesn't apply.
25
+ */
26
+ export function resolveClientJsSpecifier(source: string, importer: string | undefined): string | null {
27
+ if (!source.endsWith(CLIENT_JS_SUFFIX)) return null
28
+ if (!source.startsWith('./') && !source.startsWith('../')) return null
29
+ if (!importer) return null
30
+
31
+ const candidateBase = resolve(dirname(importer), source.slice(0, -CLIENT_JS_SUFFIX.length))
32
+ const tsxPath = `${candidateBase}.tsx`
33
+ return existsSync(tsxPath) ? tsxPath : null
34
+ }
package/src/types.ts ADDED
@@ -0,0 +1,144 @@
1
+ import type { TemplateAdapter } from '@barefootjs/jsx'
2
+
3
+ /**
4
+ * Narrow context handed to `afterEmit` once per eager pass (`writeBundle`
5
+ * for `vite build`, the dev pass for `vite dev`) — AFTER every discovered
6
+ * component's template has already been written to `templatesDir`. This is
7
+ * the one escape hatch this plugin exposes, and its shape is deliberately
8
+ * minimal:
9
+ *
10
+ * - `types`: adapter-generated `types` fragments (e.g. Go Props structs)
11
+ * this pass produced, keyed by the source file's absolute path. Raw,
12
+ * per-file, uncombined — combining them into a single backend-native
13
+ * file (stripping headers, deduping, injecting shared helpers) is a
14
+ * real per-language operation an adapter's own `/vite` subpath performs
15
+ * (see `@barefootjs/go-template/vite`'s use of `combineGoTypes`), not
16
+ * something core knows how to do generically.
17
+ * - `projectDir` / `templatesDir` / `outDir`: the same absolute paths the
18
+ * plugin itself just used to write templates and (for `outDir`) that
19
+ * Vite wrote client assets to.
20
+ * - `mode`: which eager pass just ran. Go's `components.go` (and any other
21
+ * adapter-side derived file) has to exist for `go run .` to even compile
22
+ * in dev, which is why this fires from BOTH passes, not just the build
23
+ * one — a hook named `postBuild` would misleadingly suggest otherwise.
24
+ *
25
+ * What this deliberately does NOT carry: emitted client JS. That's the
26
+ * one thing a caller must never be handed to rewrite post-compile (see
27
+ * CLAUDE.md's "never add compiler options/hooks for tool-specific output
28
+ * rewriting") — closing that door by TYPE, not by convention, is the
29
+ * point of keeping this context this narrow.
30
+ */
31
+ export interface AfterEmitContext {
32
+ /** Per-source-file `types` output, keyed by that file's absolute path.
33
+ * Empty when no discovered file in this pass produced a `types` output. */
34
+ types: Map<string, string>
35
+ /** Absolute path to the Vite project root. */
36
+ projectDir: string
37
+ /** Absolute path to the configured `templates` output dir. */
38
+ templatesDir: string
39
+ /** Absolute path to Vite's configured `build.outDir`. */
40
+ outDir: string
41
+ /** Which eager pass just ran. */
42
+ mode: 'build' | 'dev'
43
+ }
44
+
45
+ /**
46
+ * One `components` entry with per-directory compile behavior. A plain
47
+ * string is exactly equivalent to `{ dir: string }` — see
48
+ * `BarefootViteOptions.components`.
49
+ */
50
+ export interface ComponentDirEntry {
51
+ /** Source directory to scan, relative to the Vite root (or absolute). */
52
+ dir: string
53
+ /** `CompileOptions.cssLayerPrefix` for every component under `dir`:
54
+ * static class strings get `layer-{value}:` prefixes so a library's
55
+ * base classes land in a lower cascade layer than app overrides. Set
56
+ * it on library entries, leave it off app entries. */
57
+ cssLayerPrefix?: string
58
+ /** Directory NAMES to skip anywhere under `dir` (e.g. `['shared']`). */
59
+ skipDirs?: string[]
60
+ }
61
+
62
+ /**
63
+ * Public options for the `barefoot()` Vite plugin. Exactly three
64
+ * BarefootJS-specific FIELDS — everything else (bundling, hashing,
65
+ * chunking, tree-shaking, minification, dev server, `base`, `outDir`) is
66
+ * stock Vite config. Do not add more fields here; see the design doc for
67
+ * the full list of options this deliberately drops in favor of Vite's own
68
+ * equivalents (`minify` → `build.minify`, `externals` → Rollup's automatic
69
+ * chunk splitting, `clientJsBasePath`/`barefootJsPath` → `base` + manifest
70
+ * resolution, etc).
71
+ *
72
+ * The cap is on FIELDS, not on per-directory expressiveness: whether a
73
+ * directory's classes need a CSS cascade layer, or which subdirectories to
74
+ * skip, is a function of WHICH `components` entry a file came from — so
75
+ * that behavior rides on the `components` entries themselves
76
+ * (`ComponentDirEntry`) rather than becoming a 4th/5th top-level option.
77
+ */
78
+ export interface BarefootViteOptions {
79
+ /** A constructed `TemplateAdapter` instance (e.g. `new
80
+ * GoTemplateAdapter({ packageName: 'main' })`). Not a factory function —
81
+ * the plugin never constructs adapters itself. */
82
+ adapter: TemplateAdapter
83
+ /** Source directories to scan for `.tsx` components, relative to the
84
+ * Vite project root (or absolute). A plain string is exactly equivalent
85
+ * to `{ dir: string }` (a `ComponentDirEntry` with no `cssLayerPrefix`/
86
+ * `skipDirs`) — use the object form only when a directory needs one of
87
+ * those. Entries are processed in array order, and that order is also
88
+ * the precedence when the same file is reachable under more than one
89
+ * entry: the first entry wins. */
90
+ components: (string | ComponentDirEntry)[]
91
+ /**
92
+ * Where compiled templates, `ssrDefaults`, and adapter-generated types
93
+ * land — relative to the Vite project root (or absolute). This is a
94
+ * backend source directory the server-side app reads, NOT
95
+ * `build.outDir` (which is Vite's client-asset output).
96
+ *
97
+ * Optional for an adapter whose `generate()` output is ALWAYS empty
98
+ * (e.g. `CSRAdapter` — CSR has no template-language backend to point a
99
+ * `templates` dir at). When omitted, the eager pass still compiles every
100
+ * discovered component (client JS generation is unaffected) but writes
101
+ * nothing to disk on its behalf — no per-component template/ssrDefaults/
102
+ * types files, no `manifest.json`. If some discovered component turns
103
+ * out to produce a REAL (non-empty) template anyway, the eager pass
104
+ * refuses loudly instead of silently dropping it: omitting `templates`
105
+ * is a claim about the adapter's output that this plugin verifies rather
106
+ * than trusts. See `plugin.ts`'s `assertNoRealTemplateOutput`.
107
+ */
108
+ templates?: string
109
+ /**
110
+ * Optional escape hatch called once per eager pass (build AND dev), after
111
+ * templates are written, with a narrow `AfterEmitContext`. NOT a
112
+ * user-facing 4th option in the design-doc sense — it exists so an
113
+ * adapter's own `/vite` subpath (e.g. `@barefootjs/go-template/vite`) can
114
+ * wire up its own per-language post-processing (e.g. combining `types`
115
+ * into a single `components.go`) while calling this core plugin
116
+ * underneath. See `AfterEmitContext`'s docstring for what it can and
117
+ * cannot see.
118
+ */
119
+ afterEmit?: (ctx: AfterEmitContext) => Promise<void> | void
120
+ }
121
+
122
+ /**
123
+ * Shape exposed on the returned plugin's `.api` — Vite's own convention
124
+ * (a plugin may attach an `api` property "designed for other plugins or
125
+ * Vite-based tools to access") for exactly this: tooling that wants this
126
+ * plugin's resolved options without re-deriving them from `vite.config.ts`
127
+ * text. The `bf` CLI (`packages/cli/src/context.ts`) is the one consumer
128
+ * today — it uses Vite's own `loadConfigFromFile` to get the resolved
129
+ * config, finds the plugin by name (`PLUGIN_NAME`, exported from
130
+ * `plugin.ts`) in its `plugins` array, and reads `api.options.components`
131
+ * as `sourceDirs`.
132
+ *
133
+ * Populated synchronously the moment `barefoot(options)` is called —
134
+ * `options` needs no Vite lifecycle hook to have already run, deliberately:
135
+ * `loadConfigFromFile` never calls a plugin's hooks (`config`,
136
+ * `configResolved`, ...) at all, it just evaluates `vite.config.ts` and
137
+ * returns the resulting plugin instances, so anything gated behind
138
+ * `configResolved` (e.g. the plugin's own resolved absolute `componentDirs`)
139
+ * would never be visible to a caller going through that path.
140
+ */
141
+ export interface BarefootPluginApi {
142
+ /** The exact options object `barefoot()` was constructed with. */
143
+ options: BarefootViteOptions
144
+ }