@pyreon/vite-plugin 0.13.1 → 0.15.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/lib/analysis/index.js.html +1 -1
- package/lib/index.js +213 -15
- package/package.json +3 -2
- package/src/index.ts +342 -6
- package/src/tests/compat-resolve.test.ts +260 -0
- package/src/tests/cross-module-signals.test.ts +425 -0
- package/src/tests/dev-server.test.ts +167 -0
- package/src/tests/vite-plugin.test.ts +94 -54
- package/lib/index.js.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
|
@@ -36,60 +36,67 @@ function createBuildPlugin(opts?: PyreonPluginOptions) {
|
|
|
36
36
|
return plugin
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
function transform(plugin: ReturnType<typeof pyreonPlugin>, code: string, id: string) {
|
|
39
|
+
async function transform(plugin: ReturnType<typeof pyreonPlugin>, code: string, id: string) {
|
|
40
40
|
const transformHook = plugin.transform as (
|
|
41
|
-
this: { warn: (msg: string) => void },
|
|
41
|
+
this: { warn: (msg: string) => void; resolve: (id: string, importer?: string, options?: { skipSelf: boolean }) => Promise<{ id: string } | null> },
|
|
42
42
|
code: string,
|
|
43
43
|
id: string,
|
|
44
|
-
) => { code: string; map: null } | undefined
|
|
44
|
+
) => Promise<{ code: string; map: null } | undefined>
|
|
45
45
|
const warnings: string[] = []
|
|
46
|
-
return transformHook.call(
|
|
46
|
+
return transformHook.call(
|
|
47
|
+
{
|
|
48
|
+
warn: (msg: string) => warnings.push(msg),
|
|
49
|
+
resolve: async () => null, // no cross-module resolution in unit tests
|
|
50
|
+
},
|
|
51
|
+
code,
|
|
52
|
+
id,
|
|
53
|
+
)
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
// ─── HMR injection ──────────────────────────────────────────────────────────
|
|
50
57
|
|
|
51
58
|
describe('HMR injection', () => {
|
|
52
|
-
it('injects HMR accept for modules with component exports', () => {
|
|
59
|
+
it('injects HMR accept for modules with component exports', async () => {
|
|
53
60
|
const plugin = createPlugin()
|
|
54
61
|
const code = `
|
|
55
62
|
import { h } from "@pyreon/core"
|
|
56
63
|
export function App() { return h("div", null, "hello") }
|
|
57
64
|
`
|
|
58
|
-
const result = transform(plugin, code, '/src/App.tsx')
|
|
65
|
+
const result = await transform(plugin, code, '/src/App.tsx')
|
|
59
66
|
expect(result).toBeDefined()
|
|
60
67
|
expect(result!.code).toContain('import.meta.hot.accept()')
|
|
61
68
|
})
|
|
62
69
|
|
|
63
|
-
it('injects HMR for exported const components', () => {
|
|
70
|
+
it('injects HMR for exported const components', async () => {
|
|
64
71
|
const plugin = createPlugin()
|
|
65
72
|
const code = `
|
|
66
73
|
import { h } from "@pyreon/core"
|
|
67
74
|
export const Header = () => h("header", null, "nav")
|
|
68
75
|
`
|
|
69
|
-
const result = transform(plugin, code, '/src/Header.tsx')
|
|
76
|
+
const result = await transform(plugin, code, '/src/Header.tsx')
|
|
70
77
|
expect(result).toBeDefined()
|
|
71
78
|
expect(result!.code).toContain('import.meta.hot')
|
|
72
79
|
})
|
|
73
80
|
|
|
74
|
-
it('does not inject HMR for modules without component exports or signals', () => {
|
|
81
|
+
it('does not inject HMR for modules without component exports or signals', async () => {
|
|
75
82
|
const plugin = createPlugin()
|
|
76
83
|
// Only lowercase exports — no component-like names (uppercase first letter)
|
|
77
84
|
const code = `
|
|
78
85
|
export const formatDate = (d) => d.toISOString()
|
|
79
86
|
export const maxItems = 100
|
|
80
87
|
`
|
|
81
|
-
const result = transform(plugin, code, '/src/utils.tsx')
|
|
88
|
+
const result = await transform(plugin, code, '/src/utils.tsx')
|
|
82
89
|
expect(result).toBeDefined()
|
|
83
90
|
expect(result!.code).not.toContain('import.meta.hot')
|
|
84
91
|
})
|
|
85
92
|
|
|
86
|
-
it('does not inject HMR in build mode', () => {
|
|
93
|
+
it('does not inject HMR in build mode', async () => {
|
|
87
94
|
const plugin = createBuildPlugin()
|
|
88
95
|
const code = `
|
|
89
96
|
import { h } from "@pyreon/core"
|
|
90
97
|
export function App() { return h("div", null, "hello") }
|
|
91
98
|
`
|
|
92
|
-
const result = transform(plugin, code, '/src/App.tsx')
|
|
99
|
+
const result = await transform(plugin, code, '/src/App.tsx')
|
|
93
100
|
expect(result).toBeDefined()
|
|
94
101
|
expect(result!.code).not.toContain('import.meta.hot')
|
|
95
102
|
})
|
|
@@ -98,7 +105,7 @@ export function App() { return h("div", null, "hello") }
|
|
|
98
105
|
// ─── Signal rewriting ────────────────────────────────────────────────────────
|
|
99
106
|
|
|
100
107
|
describe('signal rewriting', () => {
|
|
101
|
-
it('rewrites module-scope signal() to __hmr_signal()', () => {
|
|
108
|
+
it('rewrites module-scope signal() to __hmr_signal()', async () => {
|
|
102
109
|
const plugin = createPlugin()
|
|
103
110
|
const code = `
|
|
104
111
|
import { signal } from "@pyreon/reactivity"
|
|
@@ -106,7 +113,7 @@ import { h } from "@pyreon/core"
|
|
|
106
113
|
const count = signal(0)
|
|
107
114
|
export function Counter() { return h("div", null, count()) }
|
|
108
115
|
`
|
|
109
|
-
const result = transform(plugin, code, '/src/Counter.tsx')
|
|
116
|
+
const result = await transform(plugin, code, '/src/Counter.tsx')
|
|
110
117
|
expect(result).toBeDefined()
|
|
111
118
|
expect(result!.code).toContain('__hmr_signal(')
|
|
112
119
|
expect(result!.code).toContain('"count"')
|
|
@@ -114,19 +121,45 @@ export function Counter() { return h("div", null, count()) }
|
|
|
114
121
|
expect(result!.code).toContain('__hmr_dispose')
|
|
115
122
|
})
|
|
116
123
|
|
|
117
|
-
it('rewrites exported signals', () => {
|
|
124
|
+
it('rewrites exported signals', async () => {
|
|
118
125
|
const plugin = createPlugin()
|
|
119
126
|
const code = `
|
|
120
127
|
import { signal } from "@pyreon/reactivity"
|
|
121
128
|
export const theme = signal("light")
|
|
122
129
|
export function App() { return null }
|
|
123
130
|
`
|
|
124
|
-
const result = transform(plugin, code, '/src/theme.tsx')
|
|
131
|
+
const result = await transform(plugin, code, '/src/theme.tsx')
|
|
125
132
|
expect(result).toBeDefined()
|
|
126
133
|
expect(result!.code).toContain('__hmr_signal("/src/theme.tsx", "theme", signal, "light")')
|
|
127
134
|
})
|
|
128
135
|
|
|
129
|
-
it('
|
|
136
|
+
it('rewrites generic-typed signals (signal<T>(value))', async () => {
|
|
137
|
+
// Regression for the silent-skip bug: SIGNAL_PREFIX_RE used to match
|
|
138
|
+
// `signal(` but not `signal<T>(`. Pre-rewrite TypeScript still has type
|
|
139
|
+
// parameters; declarations like `signal<string>('')` would skip HMR
|
|
140
|
+
// preservation silently and produce an empty-string-valued signal that
|
|
141
|
+
// — under a separate `__hmr_signal` interaction — could read as
|
|
142
|
+
// undefined. Discovered via PR #329 (perf-dashboard form section).
|
|
143
|
+
const plugin = createPlugin()
|
|
144
|
+
const code = `
|
|
145
|
+
import { signal } from "@pyreon/reactivity"
|
|
146
|
+
export const password = signal<string>("")
|
|
147
|
+
export const items = signal<Array<{ id: number }>>([])
|
|
148
|
+
export const count = signal<number>(0)
|
|
149
|
+
export function App() { return null }
|
|
150
|
+
`
|
|
151
|
+
const result = await transform(plugin, code, '/src/state.tsx')
|
|
152
|
+
expect(result).toBeDefined()
|
|
153
|
+
expect(result!.code).toContain(
|
|
154
|
+
'__hmr_signal("/src/state.tsx", "password", signal, "")',
|
|
155
|
+
)
|
|
156
|
+
expect(result!.code).toContain(
|
|
157
|
+
'__hmr_signal("/src/state.tsx", "items", signal, [])',
|
|
158
|
+
)
|
|
159
|
+
expect(result!.code).toContain('__hmr_signal("/src/state.tsx", "count", signal, 0)')
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('does not rewrite signal() inside functions to __hmr_signal (but injects name)', async () => {
|
|
130
163
|
const plugin = createPlugin()
|
|
131
164
|
const code = `
|
|
132
165
|
import { signal } from "@pyreon/reactivity"
|
|
@@ -136,7 +169,7 @@ export function Counter() {
|
|
|
136
169
|
return h("div", null, local())
|
|
137
170
|
}
|
|
138
171
|
`
|
|
139
|
-
const result = transform(plugin, code, '/src/Counter.tsx')
|
|
172
|
+
const result = await transform(plugin, code, '/src/Counter.tsx')
|
|
140
173
|
expect(result).toBeDefined()
|
|
141
174
|
// The signal inside the function body should NOT be rewritten to __hmr_signal
|
|
142
175
|
expect(result!.code).not.toContain('__hmr_signal')
|
|
@@ -144,7 +177,7 @@ export function Counter() {
|
|
|
144
177
|
expect(result!.code).toContain('signal(0, { name: "local" })')
|
|
145
178
|
})
|
|
146
179
|
|
|
147
|
-
it('rewrites multiple module-scope signals', () => {
|
|
180
|
+
it('rewrites multiple module-scope signals', async () => {
|
|
148
181
|
const plugin = createPlugin()
|
|
149
182
|
const code = `
|
|
150
183
|
import { signal } from "@pyreon/reactivity"
|
|
@@ -152,13 +185,13 @@ const count = signal(0)
|
|
|
152
185
|
const name = signal("world")
|
|
153
186
|
export function App() { return null }
|
|
154
187
|
`
|
|
155
|
-
const result = transform(plugin, code, '/src/App.tsx')
|
|
188
|
+
const result = await transform(plugin, code, '/src/App.tsx')
|
|
156
189
|
expect(result).toBeDefined()
|
|
157
190
|
expect(result!.code).toContain('"count"')
|
|
158
191
|
expect(result!.code).toContain('"name"')
|
|
159
192
|
})
|
|
160
193
|
|
|
161
|
-
it('handles signal with complex initial values', () => {
|
|
194
|
+
it('handles signal with complex initial values', async () => {
|
|
162
195
|
const plugin = createPlugin()
|
|
163
196
|
const code = `
|
|
164
197
|
import { signal } from "@pyreon/reactivity"
|
|
@@ -166,21 +199,21 @@ const items = signal([1, 2, 3])
|
|
|
166
199
|
const config = signal({ theme: "dark", size: 14 })
|
|
167
200
|
export function App() { return null }
|
|
168
201
|
`
|
|
169
|
-
const result = transform(plugin, code, '/src/App.tsx')
|
|
202
|
+
const result = await transform(plugin, code, '/src/App.tsx')
|
|
170
203
|
expect(result).toBeDefined()
|
|
171
204
|
expect(result!.code).toContain('__hmr_signal')
|
|
172
205
|
expect(result!.code).toContain('[1, 2, 3]')
|
|
173
206
|
expect(result!.code).toContain('{ theme: "dark", size: 14 }')
|
|
174
207
|
})
|
|
175
208
|
|
|
176
|
-
it('does not rewrite signal in build mode', () => {
|
|
209
|
+
it('does not rewrite signal in build mode', async () => {
|
|
177
210
|
const plugin = createBuildPlugin()
|
|
178
211
|
const code = `
|
|
179
212
|
import { signal } from "@pyreon/reactivity"
|
|
180
213
|
const count = signal(0)
|
|
181
214
|
export function App() { return null }
|
|
182
215
|
`
|
|
183
|
-
const result = transform(plugin, code, '/src/App.tsx')
|
|
216
|
+
const result = await transform(plugin, code, '/src/App.tsx')
|
|
184
217
|
expect(result).toBeDefined()
|
|
185
218
|
expect(result!.code).not.toContain('__hmr_signal')
|
|
186
219
|
// No signal names in production builds
|
|
@@ -188,7 +221,7 @@ export function App() { return null }
|
|
|
188
221
|
expect(result!.code).not.toContain('{ name:')
|
|
189
222
|
})
|
|
190
223
|
|
|
191
|
-
it('skips signal naming when options already provided', () => {
|
|
224
|
+
it('skips signal naming when options already provided', async () => {
|
|
192
225
|
const plugin = createPlugin()
|
|
193
226
|
const code = `
|
|
194
227
|
import { signal } from "@pyreon/reactivity"
|
|
@@ -197,7 +230,7 @@ export function App() {
|
|
|
197
230
|
return null
|
|
198
231
|
}
|
|
199
232
|
`
|
|
200
|
-
const result = transform(plugin, code, '/src/App.tsx')
|
|
233
|
+
const result = await transform(plugin, code, '/src/App.tsx')
|
|
201
234
|
expect(result).toBeDefined()
|
|
202
235
|
// Should not double-inject name
|
|
203
236
|
expect(result!.code).toContain('signal(0, { name: "custom" })')
|
|
@@ -207,38 +240,38 @@ export function App() {
|
|
|
207
240
|
// ─── File extension filtering ────────────────────────────────────────────────
|
|
208
241
|
|
|
209
242
|
describe('file extension filtering', () => {
|
|
210
|
-
it('transforms .tsx files', () => {
|
|
243
|
+
it('transforms .tsx files', async () => {
|
|
211
244
|
const plugin = createPlugin()
|
|
212
245
|
const code = `export function App() { return null }`
|
|
213
|
-
const result = transform(plugin, code, '/src/App.tsx')
|
|
246
|
+
const result = await transform(plugin, code, '/src/App.tsx')
|
|
214
247
|
expect(result).toBeDefined()
|
|
215
248
|
})
|
|
216
249
|
|
|
217
|
-
it('transforms .jsx files', () => {
|
|
250
|
+
it('transforms .jsx files', async () => {
|
|
218
251
|
const plugin = createPlugin()
|
|
219
252
|
const code = `export function App() { return null }`
|
|
220
|
-
const result = transform(plugin, code, '/src/App.jsx')
|
|
253
|
+
const result = await transform(plugin, code, '/src/App.jsx')
|
|
221
254
|
expect(result).toBeDefined()
|
|
222
255
|
})
|
|
223
256
|
|
|
224
|
-
it('ignores .ts files', () => {
|
|
257
|
+
it('ignores .ts files', async () => {
|
|
225
258
|
const plugin = createPlugin()
|
|
226
259
|
const code = `export const x = 1`
|
|
227
|
-
const result = transform(plugin, code, '/src/utils.ts')
|
|
260
|
+
const result = await transform(plugin, code, '/src/utils.ts')
|
|
228
261
|
expect(result).toBeUndefined()
|
|
229
262
|
})
|
|
230
263
|
|
|
231
|
-
it('ignores .js files', () => {
|
|
264
|
+
it('ignores .js files', async () => {
|
|
232
265
|
const plugin = createPlugin()
|
|
233
266
|
const code = `export const x = 1`
|
|
234
|
-
const result = transform(plugin, code, '/src/utils.js')
|
|
267
|
+
const result = await transform(plugin, code, '/src/utils.js')
|
|
235
268
|
expect(result).toBeUndefined()
|
|
236
269
|
})
|
|
237
270
|
|
|
238
|
-
it('handles query strings in file paths', () => {
|
|
271
|
+
it('handles query strings in file paths', async () => {
|
|
239
272
|
const plugin = createPlugin()
|
|
240
273
|
const code = `export function App() { return null }`
|
|
241
|
-
const result = transform(plugin, code, '/src/App.tsx?v=123')
|
|
274
|
+
const result = await transform(plugin, code, '/src/App.tsx?v=123')
|
|
242
275
|
expect(result).toBeDefined()
|
|
243
276
|
})
|
|
244
277
|
})
|
|
@@ -246,31 +279,31 @@ describe('file extension filtering', () => {
|
|
|
246
279
|
// ─── Compat mode ─────────────────────────────────────────────────────────────
|
|
247
280
|
|
|
248
281
|
describe('compat mode', () => {
|
|
249
|
-
it('skips Pyreon JSX transform in react compat mode', () => {
|
|
282
|
+
it('skips Pyreon JSX transform in react compat mode', async () => {
|
|
250
283
|
const plugin = createPlugin({ compat: 'react' })
|
|
251
284
|
const code = `
|
|
252
285
|
import { useState } from "react"
|
|
253
286
|
export function App() { const [x] = useState(0); return null }
|
|
254
287
|
`
|
|
255
|
-
const result = transform(plugin, code, '/src/App.tsx')
|
|
288
|
+
const result = await transform(plugin, code, '/src/App.tsx')
|
|
256
289
|
expect(result).toBeUndefined()
|
|
257
290
|
})
|
|
258
291
|
|
|
259
|
-
it('skips transform in preact compat mode', () => {
|
|
292
|
+
it('skips transform in preact compat mode', async () => {
|
|
260
293
|
const plugin = createPlugin({ compat: 'preact' })
|
|
261
|
-
const result = transform(plugin, 'export function App() { return null }', '/src/App.tsx')
|
|
294
|
+
const result = await transform(plugin, 'export function App() { return null }', '/src/App.tsx')
|
|
262
295
|
expect(result).toBeUndefined()
|
|
263
296
|
})
|
|
264
297
|
|
|
265
|
-
it('skips transform in vue compat mode', () => {
|
|
298
|
+
it('skips transform in vue compat mode', async () => {
|
|
266
299
|
const plugin = createPlugin({ compat: 'vue' })
|
|
267
|
-
const result = transform(plugin, 'export function App() { return null }', '/src/App.tsx')
|
|
300
|
+
const result = await transform(plugin, 'export function App() { return null }', '/src/App.tsx')
|
|
268
301
|
expect(result).toBeUndefined()
|
|
269
302
|
})
|
|
270
303
|
|
|
271
|
-
it('skips transform in solid compat mode', () => {
|
|
304
|
+
it('skips transform in solid compat mode', async () => {
|
|
272
305
|
const plugin = createPlugin({ compat: 'solid' })
|
|
273
|
-
const result = transform(plugin, 'export function App() { return null }', '/src/App.tsx')
|
|
306
|
+
const result = await transform(plugin, 'export function App() { return null }', '/src/App.tsx')
|
|
274
307
|
expect(result).toBeUndefined()
|
|
275
308
|
})
|
|
276
309
|
})
|
|
@@ -278,13 +311,13 @@ export function App() { const [x] = useState(0); return null }
|
|
|
278
311
|
// ─── Plugin config ───────────────────────────────────────────────────────────
|
|
279
312
|
|
|
280
313
|
describe('plugin config', () => {
|
|
281
|
-
it('sets resolve.conditions: ["bun"] for workspace source resolution', () => {
|
|
314
|
+
it('sets resolve.conditions: ["bun"] for workspace source resolution', async () => {
|
|
282
315
|
const plugin = pyreonPlugin()
|
|
283
316
|
const config = getConfigHook(plugin)({}, { command: 'serve' }) as Record<string, any>
|
|
284
317
|
expect(config.resolve.conditions).toEqual(['bun'])
|
|
285
318
|
})
|
|
286
319
|
|
|
287
|
-
it('sets JSX import source to @pyreon/core by default', () => {
|
|
320
|
+
it('sets JSX import source to @pyreon/core by default', async () => {
|
|
288
321
|
const plugin = pyreonPlugin()
|
|
289
322
|
const config = getConfigHook(plugin)({}, { command: 'serve' }) as {
|
|
290
323
|
oxc: { jsx: { importSource: string } }
|
|
@@ -292,15 +325,22 @@ describe('plugin config', () => {
|
|
|
292
325
|
expect(config.oxc.jsx.importSource).toBe('@pyreon/core')
|
|
293
326
|
})
|
|
294
327
|
|
|
295
|
-
it('
|
|
328
|
+
it('keeps JSX import source as @pyreon/core in compat mode', async () => {
|
|
329
|
+
// OXC's `importSource` is project-wide (one setting for the whole build),
|
|
330
|
+
// so pointing it at the compat package would force the compat runtime
|
|
331
|
+
// on `@pyreon/*` framework files too — which they cannot handle. Instead
|
|
332
|
+
// the plugin keeps OXC at `@pyreon/core` and redirects the resulting
|
|
333
|
+
// `@pyreon/core/jsx-runtime` import to the compat package via `resolveId`,
|
|
334
|
+
// gated on the importer (user code only). See `compat-resolve.test.ts`
|
|
335
|
+
// "framework-importer carve-out". Caught by `cpa-smoke-app-*-compat`.
|
|
296
336
|
const plugin = pyreonPlugin({ compat: 'react' })
|
|
297
337
|
const config = getConfigHook(plugin)({}, { command: 'serve' }) as {
|
|
298
338
|
oxc: { jsx: { importSource: string } }
|
|
299
339
|
}
|
|
300
|
-
expect(config.oxc.jsx.importSource).toBe('@pyreon/
|
|
340
|
+
expect(config.oxc.jsx.importSource).toBe('@pyreon/core')
|
|
301
341
|
})
|
|
302
342
|
|
|
303
|
-
it('excludes compat packages from optimizeDeps', () => {
|
|
343
|
+
it('excludes compat packages from optimizeDeps', async () => {
|
|
304
344
|
const plugin = pyreonPlugin({ compat: 'react' })
|
|
305
345
|
const config = getConfigHook(plugin)({}, { command: 'serve' }) as {
|
|
306
346
|
optimizeDeps: { exclude: string[] }
|
|
@@ -309,7 +349,7 @@ describe('plugin config', () => {
|
|
|
309
349
|
expect(config.optimizeDeps.exclude).toContain('react-dom')
|
|
310
350
|
})
|
|
311
351
|
|
|
312
|
-
it('adds SSR build config when isSsrBuild', () => {
|
|
352
|
+
it('adds SSR build config when isSsrBuild', async () => {
|
|
313
353
|
const plugin = pyreonPlugin({ ssr: { entry: './src/entry-server.ts' } })
|
|
314
354
|
const config = getConfigHook(plugin)({}, { command: 'build', isSsrBuild: true }) as {
|
|
315
355
|
build: { ssr: boolean; rollupOptions: { input: string } }
|
|
@@ -331,7 +371,7 @@ describe('virtual module resolution', () => {
|
|
|
331
371
|
expect(resolved).toBe('\0pyreon/hmr-runtime')
|
|
332
372
|
})
|
|
333
373
|
|
|
334
|
-
it('loads HMR runtime source for internal ID', () => {
|
|
374
|
+
it('loads HMR runtime source for internal ID', async () => {
|
|
335
375
|
const plugin = createPlugin()
|
|
336
376
|
const load = plugin.load as (id: string) => string | undefined
|
|
337
377
|
const source = load('\0pyreon/hmr-runtime')
|
|
@@ -341,7 +381,7 @@ describe('virtual module resolution', () => {
|
|
|
341
381
|
expect(source).toContain('__pyreon_hmr_registry__')
|
|
342
382
|
})
|
|
343
383
|
|
|
344
|
-
it('returns undefined for non-virtual IDs', () => {
|
|
384
|
+
it('returns undefined for non-virtual IDs', async () => {
|
|
345
385
|
const plugin = createPlugin()
|
|
346
386
|
const load = plugin.load as (id: string) => string | undefined
|
|
347
387
|
expect(load('/src/App.tsx')).toBeUndefined()
|
|
@@ -356,12 +396,12 @@ describe('asset request filtering', () => {
|
|
|
356
396
|
// For direct testing, we'd need to export it — instead we verify
|
|
357
397
|
// the plugin's SSR middleware config exists when ssr option is set.
|
|
358
398
|
|
|
359
|
-
it('configureServer returns middleware function when SSR enabled', () => {
|
|
399
|
+
it('configureServer returns middleware function when SSR enabled', async () => {
|
|
360
400
|
const plugin = pyreonPlugin({ ssr: { entry: './src/entry-server.ts' } })
|
|
361
401
|
expect(plugin.configureServer).toBeDefined()
|
|
362
402
|
})
|
|
363
403
|
|
|
364
|
-
it('configureServer is defined even without SSR (for context generation)', () => {
|
|
404
|
+
it('configureServer is defined even without SSR (for context generation)', async () => {
|
|
365
405
|
const plugin = pyreonPlugin()
|
|
366
406
|
expect(plugin.configureServer).toBeDefined()
|
|
367
407
|
})
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["pathJoin"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @pyreon/vite-plugin — Vite integration for Pyreon framework.\n *\n * Applies Pyreon's JSX reactive transform to .tsx, .jsx, and .pyreon files,\n * and configures Vite to use Pyreon's JSX runtime.\n *\n * ## Basic usage (SPA)\n *\n * import pyreon from \"@pyreon/vite-plugin\"\n * export default { plugins: [pyreon()] }\n *\n * ## Drop-in compat mode (zero code changes)\n *\n * import pyreon from \"@pyreon/vite-plugin\"\n * export default { plugins: [pyreon({ compat: \"react\" })] }\n *\n * Aliases `react`, `react-dom`, `vue`, `solid-js`, or `preact` imports to\n * Pyreon's compat packages — existing code works without changing imports.\n *\n * ## SSR mode\n *\n * import pyreon from \"@pyreon/vite-plugin\"\n * export default { plugins: [pyreon({ ssr: { entry: \"./src/entry-server.ts\" } })] }\n *\n * In SSR mode, the plugin adds dev server middleware that:\n * 1. Loads your server entry via Vite's `ssrLoadModule`\n * 2. Calls the exported `handler` or default export (Request → Response)\n * 3. Returns the SSR'd HTML for every non-asset request\n *\n * For production, build separately:\n * vite build # client bundle\n * vite build --ssr src/entry-server.ts --outDir dist/server # server bundle\n */\n\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { join as pathJoin } from 'node:path'\nimport { generateContext, transformJSX } from '@pyreon/compiler'\nimport type { Plugin, ViteDevServer } from 'vite'\n\n// Virtual module ID for the HMR runtime\nconst HMR_RUNTIME_ID = '\\0pyreon/hmr-runtime'\nconst HMR_RUNTIME_IMPORT = 'virtual:pyreon/hmr-runtime'\n\nexport type CompatFramework = 'react' | 'preact' | 'vue' | 'solid'\n\nexport interface PyreonPluginOptions {\n /**\n * Alias imports from an existing framework to Pyreon's compat layer.\n *\n * This lets you drop Pyreon into an existing project with zero code changes —\n * `import { useState } from \"react\"` will resolve to `@pyreon/react-compat`.\n *\n * @example\n * pyreon({ compat: \"react\" }) // react + react-dom → @pyreon/react-compat\n * pyreon({ compat: \"vue\" }) // vue → @pyreon/vue-compat\n * pyreon({ compat: \"solid\" }) // solid-js → @pyreon/solid-compat\n * pyreon({ compat: \"preact\" }) // preact + hooks + signals → @pyreon/preact-compat\n */\n compat?: CompatFramework\n\n /**\n * Enable SSR dev middleware.\n *\n * Pass an object with `entry` pointing to your server entry file.\n * The entry must export a `handler` function: `(req: Request) => Promise<Response>`\n * or a default export of the same type.\n *\n * @example\n * pyreonPlugin({ ssr: { entry: \"./src/entry-server.ts\" } })\n */\n ssr?: {\n /** Server entry file path (e.g. \"./src/entry-server.ts\") */\n entry: string\n }\n}\n\n// ── Compat JSX import sources ─────────────────────────────────────────────────\n\nconst COMPAT_JSX_SOURCE: Record<CompatFramework, string> = {\n react: '@pyreon/react-compat',\n preact: '@pyreon/preact-compat',\n vue: '@pyreon/vue-compat',\n solid: '@pyreon/solid-compat',\n}\n\n// ── Compat alias maps ─────────────────────────────────────────────────────────\n\nconst COMPAT_ALIASES: Record<CompatFramework, Record<string, string>> = {\n react: {\n react: '@pyreon/react-compat',\n 'react/jsx-runtime': '@pyreon/react-compat/jsx-runtime',\n 'react/jsx-dev-runtime': '@pyreon/react-compat/jsx-runtime',\n 'react-dom': '@pyreon/react-compat/dom',\n 'react-dom/client': '@pyreon/react-compat/dom',\n },\n preact: {\n preact: '@pyreon/preact-compat',\n 'preact/hooks': '@pyreon/preact-compat/hooks',\n 'preact/jsx-runtime': '@pyreon/preact-compat/jsx-runtime',\n 'preact/jsx-dev-runtime': '@pyreon/preact-compat/jsx-runtime',\n '@preact/signals': '@pyreon/preact-compat/signals',\n },\n vue: {\n vue: '@pyreon/vue-compat',\n 'vue/jsx-runtime': '@pyreon/vue-compat/jsx-runtime',\n 'vue/jsx-dev-runtime': '@pyreon/vue-compat/jsx-runtime',\n },\n solid: {\n 'solid-js': '@pyreon/solid-compat',\n 'solid-js/jsx-runtime': '@pyreon/solid-compat/jsx-runtime',\n 'solid-js/jsx-dev-runtime': '@pyreon/solid-compat/jsx-runtime',\n },\n}\n\n/**\n * Return the Pyreon compat target for an import specifier, or undefined if\n * the import should not be redirected.\n */\nfunction getCompatTarget(compat: CompatFramework | undefined, id: string): string | undefined {\n if (!compat) return undefined\n const aliased = COMPAT_ALIASES[compat][id]\n if (aliased) return aliased\n // OXC's JSX transform reads jsxImportSource from tsconfig (@pyreon/core),\n // not from our plugin config. Redirect JSX runtime imports in compat mode.\n if (id === '@pyreon/core/jsx-runtime' || id === '@pyreon/core/jsx-dev-runtime') {\n if (compat === 'react') return '@pyreon/react-compat/jsx-runtime'\n if (compat === 'preact') return '@pyreon/preact-compat/jsx-runtime'\n if (compat === 'vue') return '@pyreon/vue-compat/jsx-runtime'\n if (compat === 'solid') return '@pyreon/solid-compat/jsx-runtime'\n }\n return undefined\n}\n\nexport default function pyreonPlugin(options?: PyreonPluginOptions): Plugin {\n const ssrConfig = options?.ssr\n const compat = options?.compat\n let isBuild = false\n let projectRoot = ''\n\n return {\n name: 'pyreon',\n enforce: 'pre',\n\n config(userConfig, env) {\n isBuild = env.command === 'build'\n // Capture the project root for package resolution in resolveId\n projectRoot = userConfig.root ?? process.cwd()\n\n // Tell Vite's dep scanner not to pre-bundle the aliased framework imports —\n // they resolve to workspace packages via our resolveId hook, not node_modules.\n const optimizeDepsExclude = compat ? Object.keys(COMPAT_ALIASES[compat]) : []\n\n const jsxSource = compat ? COMPAT_JSX_SOURCE[compat] : '@pyreon/core'\n\n return {\n // Use \"bun\" condition for workspace resolution — source .ts/.tsx files\n // for HMR, fast refresh, and type-safe imports.\n resolve: { conditions: ['bun'] },\n optimizeDeps: {\n exclude: optimizeDepsExclude,\n },\n // Vite 8 uses oxc for JSX transform (not esbuildOptions or rolldownOptions)\n oxc: {\n jsx: {\n runtime: 'automatic',\n importSource: jsxSource,\n },\n },\n // In SSR build mode, configure the entry\n ...(env.isSsrBuild && ssrConfig\n ? {\n build: {\n ssr: true,\n rollupOptions: {\n input: ssrConfig.entry,\n },\n },\n }\n : {}),\n }\n },\n\n // ── Virtual module + compat alias resolution ─────────────────────────────\n async resolveId(id, importer) {\n if (id === HMR_RUNTIME_IMPORT) return HMR_RUNTIME_ID\n const target = getCompatTarget(compat, id)\n if (!target) return\n\n // Vite 8 resolves the \"bun\" condition natively via resolve.conditions.\n // Delegate to Vite's resolver instead of manual package.json parsing.\n const resolved = await this.resolve(target, importer, { skipSelf: true })\n return resolved?.id\n },\n\n load(id) {\n if (id === HMR_RUNTIME_ID) {\n return HMR_RUNTIME_SOURCE\n }\n },\n\n transform(code, id, transformOptions) {\n const ext = getExt(id)\n if (ext !== '.tsx' && ext !== '.jsx' && ext !== '.pyreon') return\n\n // In compat mode, skip Pyreon's reactive JSX transform but apply\n // attribute renames (className → class, htmlFor → for) so source code\n // that uses React-style attribute names works correctly.\n if (compat === 'react' || compat === 'preact' || compat === 'vue' || compat === 'solid') {\n if (compat === 'react' || compat === 'preact') {\n const transformed = transformCompatAttributes(code)\n if (transformed !== code) return { code: transformed, map: null }\n }\n return\n }\n\n // Vite passes `ssr: true` when transforming for the SSR module graph\n // (both build --ssr and dev `ssrLoadModule`). The compiler emits plain\n // `h()` calls in that mode so `runtime-server` can render to a string.\n const isSsr = transformOptions?.ssr === true\n const result = transformJSX(code, id, { ssr: isSsr })\n // Surface compiler warnings in the terminal\n for (const w of result.warnings) {\n this.warn(`${w.message} (${id}:${w.line}:${w.column})`)\n }\n\n let output = result.code\n\n // ── Dev-only transforms ────────────────────────────────────────────\n if (!isBuild) {\n output = injectHmr(output, id)\n // Inject debug names for signal() calls not rewritten by HMR\n output = injectSignalNames(output)\n }\n\n return { code: output, map: null }\n },\n\n // ── SSR dev middleware ───────────────────────────────────────────────────\n configureServer(server: ViteDevServer) {\n // Generate .pyreon/context.json for AI tools on dev server start\n generateProjectContext(projectRoot)\n\n // Debounced regeneration on file changes\n let contextTimer: ReturnType<typeof setTimeout> | null = null\n server.watcher.on('change', (file) => {\n if (/\\.(tsx|jsx|ts|js)$/.test(file) && !file.includes('node_modules')) {\n if (contextTimer) clearTimeout(contextTimer)\n contextTimer = setTimeout(() => generateProjectContext(projectRoot), 500)\n }\n })\n\n if (!ssrConfig) return\n\n // Return a function so the middleware runs AFTER Vite's built-in middleware\n // (static files, HMR, etc.) — only handle requests that Vite doesn't serve.\n return () => {\n server.middlewares.use(async (req, res, next) => {\n if (req.method !== 'GET') return next()\n const url = req.url ?? '/'\n if (isAssetRequest(url)) return next()\n\n try {\n await handleSsrRequest(server, ssrConfig.entry, url, req, res, next)\n } catch (err) {\n server.ssrFixStacktrace(err as Error)\n next(err)\n }\n })\n }\n },\n }\n}\n\nasync function handleSsrRequest(\n server: ViteDevServer,\n entry: string,\n url: string,\n req: import('node:http').IncomingMessage,\n res: import('node:http').ServerResponse,\n next: (err?: unknown) => void,\n): Promise<void> {\n const mod = await server.ssrLoadModule(entry)\n const handler = mod.handler ?? mod.default\n\n if (typeof handler !== 'function') {\n next()\n return\n }\n\n const origin = `http://${req.headers.host ?? 'localhost'}`\n const fullUrl = new URL(url, origin)\n const request = new Request(fullUrl.href, {\n method: req.method ?? 'GET',\n headers: Object.entries(req.headers).reduce((h, [k, v]) => {\n if (v) h.set(k, Array.isArray(v) ? v.join(', ') : v)\n return h\n }, new Headers()),\n })\n\n const response: Response = await handler(request)\n let html = await response.text()\n\n html = await server.transformIndexHtml(url, html)\n\n res.statusCode = response.status\n response.headers.forEach((v, k) => {\n res.setHeader(k, v)\n })\n res.end(html)\n}\n\n// ── AI context generation ─────────────────────────────────────────────────────\n\n/**\n * Generate .pyreon/context.json — project map for AI coding assistants.\n * Delegates to @pyreon/compiler's unified project scanner.\n */\nfunction generateProjectContext(root: string): void {\n try {\n const context = generateContext(root)\n const outDir = pathJoin(root, '.pyreon')\n if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true })\n writeFileSync(pathJoin(outDir, 'context.json'), JSON.stringify(context, null, 2), 'utf-8')\n } catch {\n // Silently fail — context generation is best-effort\n }\n}\n\n// ── HMR injection ─────────────────────────────────────────────────────────────\n\n/**\n * Regex that detects signal declarations (prefix + variable name).\n * The arguments are extracted via balanced-paren matching in `injectHmr`.\n * A brace-depth check filters out matches inside functions/blocks — only\n * module-scope (depth 0) signals are rewritten for HMR state preservation.\n */\nconst SIGNAL_PREFIX_RE = /^((?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*)signal\\(/gm\n\n/**\n * Detect whether the module exports any component-like functions\n * (uppercase first letter — standard convention for JSX components).\n */\nconst EXPORT_COMPONENT_RE =\n /export\\s+(?:default\\s+)?(?:function\\s+([A-Z]\\w*)|const\\s+([A-Z]\\w*)\\s*[=:])/\n\nfunction skipStringLiteral(code: string, start: number, quote: string): number {\n let j = start + 1\n while (j < code.length) {\n if (code[j] === '\\\\') {\n j += 2\n continue\n }\n if (code[j] === quote) break\n j++\n }\n return j\n}\n\nfunction extractBalancedArgs(code: string, start: number): string | null {\n let depth = 1\n for (let i = start; i < code.length; i++) {\n const ch = code[i]\n if (ch === '(') depth++\n else if (ch === ')') {\n depth--\n if (depth === 0) return code.slice(start, i)\n } else if (ch === '\"' || ch === \"'\" || ch === '`') {\n i = skipStringLiteral(code, i, ch)\n }\n }\n return null\n}\n\n/**\n * Compute brace depth at position `pos` — returns 0 for module scope.\n * Skips string literals to avoid counting braces inside strings.\n */\nfunction braceDepthAt(code: string, pos: number): number {\n let depth = 0\n for (let i = 0; i < pos; i++) {\n const ch = code[i]\n if (ch === '{') depth++\n else if (ch === '}') depth--\n else if (ch === '\"' || ch === \"'\" || ch === '`') {\n i = skipStringLiteral(code, i, ch)\n }\n }\n return depth\n}\n\n/** Rewrite module-scope `signal()` calls to `__hmr_signal()` for state preservation. */\nfunction rewriteSignals(code: string, moduleId: string): string {\n const escapedId = JSON.stringify(moduleId)\n const matches: {\n start: number\n end: number\n prefix: string\n name: string\n args: string\n }[] = []\n let m: RegExpExecArray | null = SIGNAL_PREFIX_RE.exec(code)\n while (m !== null) {\n const argsStart = m.index + m[0].length\n const args = extractBalancedArgs(code, argsStart)\n if (args === null) {\n m = SIGNAL_PREFIX_RE.exec(code)\n continue // unbalanced — skip\n }\n // Only rewrite module-scope signals (brace depth 0).\n if (braceDepthAt(code, m.index) === 0) {\n matches.push({\n start: m.index,\n end: argsStart + args.length + 1, // +1 for closing paren\n prefix: m[1] ?? '',\n name: m[2] ?? '',\n args,\n })\n }\n m = SIGNAL_PREFIX_RE.exec(code)\n }\n SIGNAL_PREFIX_RE.lastIndex = 0\n\n // Replace in reverse to preserve offsets\n let output = code\n for (let i = matches.length - 1; i >= 0; i--) {\n const { start, end, prefix, name, args } = matches[i] as (typeof matches)[number]\n const replacement = `${prefix}__hmr_signal(${escapedId}, ${JSON.stringify(name)}, signal, ${args})`\n output = output.slice(0, start) + replacement + output.slice(end)\n }\n return output\n}\n\n/** Check if an argument string contains a top-level comma (i.e. has multiple arguments). */\nfunction hasMultipleArgs(args: string): boolean {\n let depth = 0\n for (const ch of args) {\n if (ch === '(' || ch === '[' || ch === '{') depth++\n else if (ch === ')' || ch === ']' || ch === '}') depth--\n else if (ch === ',' && depth === 0) return true\n }\n return false\n}\n\n/**\n * Inject `{ name: \"varName\" }` into signal() calls that don't already have\n * an options argument. Only runs in dev mode for debugging/devtools.\n *\n * `const count = signal(0)` → `const count = signal(0, { name: \"count\" })`\n *\n * Module-scope signals rewritten to __hmr_signal() are naturally skipped\n * because the regex matches `signal(` not `__hmr_signal(`.\n */\nfunction injectSignalNames(code: string): string {\n const re = /(?:const|let)\\s+(\\w+)\\s*=\\s*signal\\(/gm\n const matches: { start: number; end: number; name: string; args: string }[] = []\n\n let m: RegExpExecArray | null = re.exec(code)\n while (m !== null) {\n const argsStart = m.index + m[0].length\n const args = extractBalancedArgs(code, argsStart)\n if (args !== null && !hasMultipleArgs(args)) {\n matches.push({ start: argsStart, end: argsStart + args.length, name: m[1] ?? '', args })\n }\n m = re.exec(code)\n }\n re.lastIndex = 0\n\n let output = code\n for (let i = matches.length - 1; i >= 0; i--) {\n const { start, end, name, args } = matches[i] as (typeof matches)[number]\n output = `${output.slice(0, start)}${args}, { name: ${JSON.stringify(name)} }${output.slice(end)}`\n }\n return output\n}\n\nfunction injectHmr(code: string, moduleId: string): string {\n const hasSignals = SIGNAL_PREFIX_RE.test(code)\n SIGNAL_PREFIX_RE.lastIndex = 0\n\n const hasComponentExport = EXPORT_COMPONENT_RE.test(code)\n\n // Only inject HMR if the module exports components or has module-scope signals\n if (!hasComponentExport && !hasSignals) return code\n\n let output = hasSignals ? rewriteSignals(code, moduleId) : code\n\n // Build the HMR footer\n const escapedId = JSON.stringify(moduleId)\n const lines: string[] = []\n\n if (hasSignals) {\n lines.push(`import { __hmr_signal, __hmr_dispose } from \"${HMR_RUNTIME_IMPORT}\";`)\n }\n\n lines.push(`if (import.meta.hot) {`)\n\n if (hasSignals) {\n lines.push(` import.meta.hot.dispose(() => __hmr_dispose(${escapedId}));`)\n }\n\n lines.push(` import.meta.hot.accept();`)\n lines.push(`}`)\n\n output = `${output}\\n\\n${lines.join('\\n')}\\n`\n\n return output\n}\n\n// ── Compat attribute transforms ──────────────────────────────────────────────\n\n/**\n * Transform React-style JSX attribute names to standard HTML attribute names.\n * This is a lightweight string transform that runs on JSX source before OXC's\n * JSX transform converts it to jsx() calls.\n *\n * - `className` → `class`\n * - `htmlFor` → `for`\n *\n * Only matches attribute position in JSX (after `<tag ` or whitespace).\n * Does not transform property access (e.g. `props.className` stays as-is since\n * the compat JSX runtime handles that at call time).\n */\nfunction transformCompatAttributes(code: string): string {\n // Match className/htmlFor in JSX attribute position:\n // After < and tag name, or after whitespace between attributes\n // Pattern: word boundary + attribute name + = (with optional whitespace)\n return code\n .replace(/(\\s)className(\\s*=)/g, '$1class$2')\n .replace(/(\\s)htmlFor(\\s*=)/g, '$1for$2')\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction getExt(id: string): string {\n const clean = id.split('?')[0] ?? id\n const dot = clean.lastIndexOf('.')\n return dot >= 0 ? clean.slice(dot) : ''\n}\n\n/** Skip Vite-handled asset requests (CSS, images, HMR, etc.) */\nfunction isAssetRequest(url: string): boolean {\n return (\n url.startsWith('/@') || // @vite/client, @id, @fs, etc.\n url.startsWith('/__') || // __open-in-editor, etc.\n url.includes('/node_modules/') ||\n /\\.(css|js|ts|tsx|jsx|json|ico|png|jpg|jpeg|gif|svg|woff2?|ttf|eot|map)(\\?|$)/.test(url)\n )\n}\n\n// ── HMR runtime source (served as virtual module) ─────────────────────────────\n//\n// Inlined here so it's available without a filesystem read. This is the\n// compiled-to-JS version of hmr-runtime.ts — kept in sync manually.\n\nconst HMR_RUNTIME_SOURCE = `\nconst REGISTRY_KEY = \"__pyreon_hmr_registry__\";\n\nfunction getRegistry() {\n if (!globalThis[REGISTRY_KEY]) {\n globalThis[REGISTRY_KEY] = new Map();\n }\n return globalThis[REGISTRY_KEY];\n}\n\nconst moduleSignals = new Map();\n\nexport function __hmr_signal(moduleId, name, signalFn, initialValue) {\n const registry = getRegistry();\n const saved = registry.get(moduleId);\n const value = saved?.has(name) ? saved.get(name) : initialValue;\n const s = signalFn(value, { name: name });\n\n let mod = moduleSignals.get(moduleId);\n if (!mod) {\n mod = { entries: new Map() };\n moduleSignals.set(moduleId, mod);\n }\n mod.entries.set(name, s);\n\n return s;\n}\n\nexport function __hmr_dispose(moduleId) {\n const mod = moduleSignals.get(moduleId);\n if (!mod) return;\n\n const registry = getRegistry();\n const saved = new Map();\n for (const [name, s] of mod.entries) {\n saved.set(name, s.peek());\n }\n registry.set(moduleId, saved);\n moduleSignals.delete(moduleId);\n}\n`\n"],"mappings":"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"}
|
package/lib/types/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/index.ts"],"mappings":";;;KA2CY,eAAA;AAAA,UAEK,mBAAA;;;;;;;;;;;;;EAaf,MAAA,GAAS,eAAA;;;;;;;;;;;EAYT,GAAA;gEAEE,KAAA;EAAA;AAAA;AAAA,iBA6DoB,YAAA,CAAa,OAAA,GAAU,mBAAA,GAAsB,MAAA"}
|