@pyreon/vite-plugin 0.22.0 → 0.24.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/README.md +97 -25
- package/lib/analysis/index.js.html +1 -1
- package/lib/index.js +388 -22
- package/lib/types/index.d.ts +128 -2
- package/package.json +2 -2
- package/src/index.ts +631 -18
- package/src/tests/cache-eviction-on-delete.test.ts +187 -0
- package/src/tests/dev-server.test.ts +5 -1
- package/src/tests/lpih-auto-bridge.test.ts +408 -0
- package/src/tests/lpih-injection.test.ts +559 -0
- package/src/tests/vite-plugin.test.ts +5 -2
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @pyreon/vite-plugin
|
|
2
2
|
|
|
3
|
-
Vite plugin for
|
|
3
|
+
Vite plugin for Pyreon — JSX transform, signal-preserving HMR, SSR middleware, islands auto-registry, compat aliasing.
|
|
4
|
+
|
|
5
|
+
`@pyreon/vite-plugin` is the single Vite integration Pyreon needs. It wires `@pyreon/compiler` into Vite's transform pipeline, sets `resolve.conditions: ["bun"]` so workspace source files resolve via the `bun` condition, configures the JSX runtime to `@pyreon/core`, and provides signal-preserving HMR (top-level `signal()` values survive hot reload). Optional features: SSR dev middleware (`ssr.entry`), an auto-discovered islands registry (`islands: true`, the `virtual:pyreon/islands-registry` module fed to `hydrateIslandsAuto()`), drop-in compat-mode aliasing (`compat: 'react' | 'preact' | 'vue' | 'solid' | 'svelte'`), and the opt-in compile-time rocketstyle wrapper collapse (`collapse: true`, build-only).
|
|
4
6
|
|
|
5
7
|
## Install
|
|
6
8
|
|
|
@@ -8,7 +10,7 @@ Vite plugin for the Pyreon framework. Applies the Pyreon JSX reactive transform
|
|
|
8
10
|
bun add -D @pyreon/vite-plugin
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
## Quick
|
|
13
|
+
## Quick start (SPA)
|
|
12
14
|
|
|
13
15
|
```ts
|
|
14
16
|
// vite.config.ts
|
|
@@ -20,21 +22,30 @@ export default defineConfig({
|
|
|
20
22
|
})
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
`tsconfig.json`:
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
```jsonc
|
|
28
|
+
{
|
|
29
|
+
"extends": "@pyreon/typescript/app",
|
|
30
|
+
"compilerOptions": {
|
|
31
|
+
"jsx": "react-jsx",
|
|
32
|
+
"jsxImportSource": "@pyreon/core"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## SSR dev mode
|
|
26
38
|
|
|
27
39
|
```ts
|
|
28
40
|
// vite.config.ts
|
|
29
41
|
import pyreon from '@pyreon/vite-plugin'
|
|
30
|
-
import { defineConfig } from 'vite'
|
|
31
42
|
|
|
32
|
-
export default
|
|
43
|
+
export default {
|
|
33
44
|
plugins: [pyreon({ ssr: { entry: './src/entry-server.ts' } })],
|
|
34
|
-
}
|
|
45
|
+
}
|
|
35
46
|
```
|
|
36
47
|
|
|
37
|
-
|
|
48
|
+
The entry must export a `handler` (or default export) of shape `(req: Request) => Promise<Response>`:
|
|
38
49
|
|
|
39
50
|
```tsx
|
|
40
51
|
// src/entry-server.ts
|
|
@@ -43,35 +54,96 @@ import App from './App'
|
|
|
43
54
|
|
|
44
55
|
export async function handler(req: Request): Promise<Response> {
|
|
45
56
|
const html = await renderToString(<App />)
|
|
46
|
-
return new Response(html, {
|
|
47
|
-
headers: { 'Content-Type': 'text/html' },
|
|
48
|
-
})
|
|
57
|
+
return new Response(html, { headers: { 'Content-Type': 'text/html' } })
|
|
49
58
|
}
|
|
50
59
|
```
|
|
51
60
|
|
|
52
|
-
|
|
61
|
+
Production builds:
|
|
53
62
|
|
|
54
63
|
```bash
|
|
55
64
|
vite build # client bundle
|
|
56
65
|
vite build --ssr src/entry-server.ts --outDir dist/server # server bundle
|
|
57
66
|
```
|
|
58
67
|
|
|
59
|
-
##
|
|
68
|
+
## Drop-in compat mode
|
|
69
|
+
|
|
70
|
+
Alias an existing framework's imports to Pyreon's compat layer — zero code changes:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
pyreon({ compat: 'react' }) // react + react-dom → @pyreon/react-compat
|
|
74
|
+
pyreon({ compat: 'preact' }) // preact + hooks + signals → @pyreon/preact-compat
|
|
75
|
+
pyreon({ compat: 'vue' }) // vue → @pyreon/vue-compat
|
|
76
|
+
pyreon({ compat: 'solid' }) // solid-js → @pyreon/solid-compat
|
|
77
|
+
pyreon({ compat: 'svelte' }) // svelte + svelte/store → @pyreon/svelte-compat
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Framework-internal `@pyreon/*` files are detected and skip the redirect so published `@pyreon/zero` etc. still load their real JSX runtime.
|
|
81
|
+
|
|
82
|
+
## Islands auto-registry
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
pyreon({ islands: true }) // default on
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Pre-scans `island(() => import('PATH'), { name, hydrate })` calls at `buildStart` and emits `virtual:pyreon/islands-registry`. Consume it in your client entry:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// src/entry-client.ts
|
|
92
|
+
import { hydrateIslandsAuto } from '@pyreon/server/client'
|
|
93
|
+
import islands from 'virtual:pyreon/islands-registry'
|
|
94
|
+
|
|
95
|
+
hydrateIslandsAuto(islands)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`hydrate: 'never'` islands are deliberately OMITTED from the registry — the strategy ships zero client JS, so registering a loader (which would pull the component into the client bundle graph) would defeat it. Manual `hydrateIslands({ … })` stays public for non-Vite consumers.
|
|
99
|
+
|
|
100
|
+
## Rocketstyle collapse (opt-in, build-only)
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
pyreon({ collapse: true })
|
|
104
|
+
// or with overrides
|
|
105
|
+
pyreon({ collapse: { sources: ['@pyreon/ui-components'], components: ['Button'] } })
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
A literal-prop rocketstyle call site (`<Button state="primary" size="medium">Save</Button>`) collapses from a 5-layer wrapper mount into one `_rsCollapse` cloneNode. The plugin SSR-resolves the real component twice (light + dark) and the compiler bakes the classes into a `_tpl` template. **Build-only** by design — dev keeps the normal mount so theme-source HMR edits stay reactive.
|
|
109
|
+
|
|
110
|
+
## Options
|
|
111
|
+
|
|
112
|
+
| Option | Type | Description |
|
|
113
|
+
| ------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
114
|
+
| `compat` | `'react' \| 'preact' \| 'vue' \| 'solid' \| 'svelte'` | Alias an existing framework's imports to the matching `@pyreon/*-compat` package. |
|
|
115
|
+
| `ssr.entry` | `string` | Server entry path. Enables SSR dev middleware. |
|
|
116
|
+
| `islands` | `boolean` | Auto-discover `island()` declarations into `virtual:pyreon/islands-registry`. Default `true`. |
|
|
117
|
+
| `collapse` | `boolean \| PyreonCollapseOptions` | Opt-in compile-time rocketstyle wrapper collapse. OFF by default. Build-only. |
|
|
118
|
+
|
|
119
|
+
`PyreonCollapseOptions`: `sources?: string[]` (default `['@pyreon/ui-components']`), `components?: string[]` (optional local-name allowlist), `provider?: { name, source }` (default `PyreonUI@@pyreon/ui-core`), `theme?: { name, source }` (default `theme@@pyreon/ui-theme`), `mode?: { name, source }` (default `useMode@@pyreon/ui-core`).
|
|
120
|
+
|
|
121
|
+
## What it does
|
|
122
|
+
|
|
123
|
+
- Wires `@pyreon/compiler`'s JSX reactive transform into `.tsx` / `.jsx` / `.pyreon` files (auto-call signals, hoist static subtrees, `_tpl` + `_bind`).
|
|
124
|
+
- Sets `resolve.conditions: ["bun"]` so Pyreon workspace source files resolve through the `bun` condition (no separate build step in dev).
|
|
125
|
+
- Configures the JSX runtime to `@pyreon/core` via `esbuild.jsx = 'automatic'` + `jsxImportSource`.
|
|
126
|
+
- In dev: auto-injects debug names into `signal()` calls so devtools show meaningful labels.
|
|
127
|
+
- In dev SSR: catch-all middleware loads the server entry via `ssrLoadModule` and renders every non-asset request.
|
|
128
|
+
- Provides signal-preserving HMR via `virtual:pyreon/hmr-runtime` — top-level signal values survive hot reload.
|
|
129
|
+
- Component-level fast-refresh: edits to a route component re-render in place via the router's `_hmrSwap` coordinator (registered on `globalThis.__pyreon_hmr_swap__`).
|
|
130
|
+
- Pre-scans signal exports across files so cross-module signal references auto-call correctly.
|
|
131
|
+
|
|
132
|
+
## Gotchas
|
|
133
|
+
|
|
134
|
+
- **Vite's config bundler hardcodes `conditions: ["node"]`** — plugin source changes are INVISIBLE to a running dev server until `lib/` is rebuilt. After editing the plugin, `bun run --filter='@pyreon/vite-plugin' build` + restart Vite.
|
|
135
|
+
- **Compat-mode applies `jsxImportSource`** automatically for the user's code. Set `jsxImportSource: "@pyreon/<compat>-compat"` in your tsconfig for type resolution.
|
|
136
|
+
- **`collapse` is build-only by design.** Dev keeps the normal mount (HMR-reactive); the plugin emits `this.info('[Pyreon] collapse is build-only …')` once per dev process if `collapse: true` is set in `vite dev`.
|
|
137
|
+
- **HMR accept callback uses the fresh module Vite hands it** — NOT a re-run of the lazy import thunk (that would return the frozen `?t=` old module).
|
|
60
138
|
|
|
61
|
-
|
|
139
|
+
## Peer dependencies
|
|
62
140
|
|
|
63
|
-
|
|
141
|
+
- `vite >= 8.0.0`
|
|
64
142
|
|
|
65
|
-
|
|
143
|
+
## Documentation
|
|
66
144
|
|
|
67
|
-
|
|
68
|
-
| ----------- | -------- | --------------------------------------------------- |
|
|
69
|
-
| `ssr.entry` | `string` | Server entry file path. Enables SSR dev middleware. |
|
|
145
|
+
Full docs: [docs.pyreon.dev/docs/vite-plugin](https://docs.pyreon.dev/docs/vite-plugin) (or `docs/docs/vite-plugin.md` in this repo).
|
|
70
146
|
|
|
71
|
-
##
|
|
147
|
+
## License
|
|
72
148
|
|
|
73
|
-
|
|
74
|
-
- Sets `esbuild.jsx` to `automatic` with `@pyreon/core` as the JSX import source.
|
|
75
|
-
- Transforms `.tsx`, `.jsx`, and `.pyreon` files through `@pyreon/compiler` for reactive JSX optimizations.
|
|
76
|
-
- In dev mode, auto-injects debug names into `signal()` calls so devtools show meaningful labels instead of "anonymous".
|
|
77
|
-
- In SSR mode, adds a catch-all middleware that renders pages through your server entry with full HMR support.
|
|
149
|
+
MIT
|
|
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
|
|
|
5386
5386
|
</script>
|
|
5387
5387
|
<script>
|
|
5388
5388
|
/*<!--*/
|
|
5389
|
-
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src/index.ts","uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src/index.ts","uid":"e04d9c6c-1"}]},{"name":"rocketstyle-collapse-C4eMAnwR.js","children":[{"name":"src/rocketstyle-collapse.ts","uid":"e04d9c6c-3"}]}],"isRoot":true},"nodeParts":{"e04d9c6c-1":{"renderedLength":45559,"gzipLength":14773,"brotliLength":0,"metaUid":"e04d9c6c-0"},"e04d9c6c-3":{"renderedLength":3424,"gzipLength":1530,"brotliLength":0,"metaUid":"e04d9c6c-2"}},"nodeMetas":{"e04d9c6c-0":{"id":"/src/index.ts","moduleParts":{"index.js":"e04d9c6c-1"},"imported":[{"uid":"e04d9c6c-4"},{"uid":"e04d9c6c-5"},{"uid":"e04d9c6c-6"},{"uid":"e04d9c6c-2","dynamic":true},{"uid":"e04d9c6c-7","dynamic":true}],"importedBy":[],"isEntry":true},"e04d9c6c-2":{"id":"/src/rocketstyle-collapse.ts","moduleParts":{"rocketstyle-collapse-C4eMAnwR.js":"e04d9c6c-3"},"imported":[{"uid":"e04d9c6c-8","dynamic":true}],"importedBy":[{"uid":"e04d9c6c-0"}]},"e04d9c6c-4":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"e04d9c6c-0"}]},"e04d9c6c-5":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"e04d9c6c-0"}]},"e04d9c6c-6":{"id":"@pyreon/compiler","moduleParts":{},"imported":[],"importedBy":[{"uid":"e04d9c6c-0"}]},"e04d9c6c-7":{"id":"node:fs/promises","moduleParts":{},"imported":[],"importedBy":[{"uid":"e04d9c6c-0"}]},"e04d9c6c-8":{"id":"vite","moduleParts":{},"imported":[],"importedBy":[{"uid":"e04d9c6c-2"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
|
|
5390
5390
|
|
|
5391
5391
|
const run = () => {
|
|
5392
5392
|
const width = window.innerWidth;
|