vite-plugin-hyperapp 1.3.1 → 2.0.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 +272 -120
- package/dist/hmr/runtime.d.ts +4 -0
- package/dist/hmr/runtime.js +21 -0
- package/dist/hmr/runtime.js.map +1 -0
- package/dist/hmr/vite.d.ts +2 -0
- package/dist/hmr/vite.js +71 -0
- package/dist/hmr/vite.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx/jsx-dev-runtime.d.ts +3 -0
- package/dist/jsx/jsx-dev-runtime.js +4 -0
- package/dist/jsx/jsx-dev-runtime.js.map +1 -0
- package/dist/jsx/jsx-runtime.d.ts +20 -0
- package/dist/jsx/jsx-runtime.js +28 -0
- package/dist/jsx/jsx-runtime.js.map +1 -0
- package/dist/jsx/vite.d.ts +2 -0
- package/dist/jsx/vite.js +20 -0
- package/dist/jsx/vite.js.map +1 -0
- package/dist/safari-sourcemaps/vite.d.ts +2 -0
- package/dist/safari-sourcemaps/vite.js +33 -0
- package/dist/safari-sourcemaps/vite.js.map +1 -0
- package/dist/ssr/index.d.ts +1 -0
- package/dist/ssr/index.js +2 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/ssr/render-to-string.d.ts +8 -0
- package/dist/ssr/render-to-string.js +10 -0
- package/dist/ssr/render-to-string.js.map +1 -0
- package/dist/ssr/vdom-html.d.ts +3 -0
- package/dist/ssr/vdom-html.js +131 -0
- package/dist/ssr/vdom-html.js.map +1 -0
- package/package.json +27 -32
- package/index.d.ts +0 -10
- package/index.js +0 -62
- package/jsx.d.ts +0 -59
- package/jsx.js +0 -13
- package/ssr.d.ts +0 -12
- package/ssr.js +0 -17
package/README.md
CHANGED
|
@@ -1,84 +1,173 @@
|
|
|
1
|
+
# Vite Hyperapp Plugin
|
|
1
2
|
|
|
2
|
-
|
|
3
|
+
Use Vite 8 to develop and build Hyperapp apps, with support for JSX/TSX, HMR and SSR.
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
## Get started
|
|
5
6
|
|
|
6
|
-
-
|
|
7
|
-
- Hot module reloading (HMR)
|
|
8
|
-
- Server-side rendering (SSR)
|
|
9
|
-
|
|
10
|
-
## Get Started
|
|
11
|
-
|
|
12
|
-
To get up and running with Hyperapp and Vite in a few seconds, use [create-vite-hyperapp](https://github.com/zaceno/create-vite-hyperapp):
|
|
7
|
+
In a Vite project, install `hyperapp` as a dependency and `vite-plugin-hyperapp` as a development-dependency:
|
|
13
8
|
|
|
14
9
|
```sh
|
|
15
|
-
|
|
10
|
+
npm install hyperapp
|
|
11
|
+
npm install -D vite vite-plugin-hyperapp
|
|
16
12
|
```
|
|
17
13
|
|
|
18
|
-
>
|
|
19
|
-
|
|
20
|
-
The starter will ask you for a folder in which to scaffold the project, and it will also ask if you would like to use typescript and/or SSR.
|
|
21
|
-
|
|
14
|
+
> If you intend to use SSR, you will want to install `vite-plugin-hyperapp` as a regular dependency since the server needs to `import {renderToString} from 'vite-plugin-hyperapp/ssr'`
|
|
22
15
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
In case you want to install manually, you need a project folder with `vite` installed, and a `vite.config.js` ready to go. Then you can install the vite-plugin for hyperapp, and enable it in the config:
|
|
26
|
-
|
|
27
|
-
```sh
|
|
28
|
-
> npm install vite-plugin-hyperapp
|
|
29
|
-
```
|
|
16
|
+
Add the plugin to your Vite config:
|
|
30
17
|
|
|
31
18
|
```js
|
|
32
19
|
// vite.config.js
|
|
33
|
-
import { defineConfig } from
|
|
34
|
-
import hyperapp from
|
|
20
|
+
import { defineConfig } from 'vite'
|
|
21
|
+
import { hyperapp } from 'vite-plugin-hyperapp'
|
|
35
22
|
|
|
36
23
|
export default defineConfig({
|
|
37
24
|
plugins: [hyperapp()],
|
|
38
25
|
})
|
|
39
26
|
```
|
|
40
|
-
> Options are passed as an object to `hyperapp({...})`. Available options described below.
|
|
41
27
|
|
|
42
|
-
|
|
28
|
+
Here is a small app to try it with:
|
|
43
29
|
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
"jsxFragmentFactory": "jsxFragment"
|
|
30
|
+
```html
|
|
31
|
+
<!-- index.html -->
|
|
32
|
+
<main id="app"></main>
|
|
33
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
49
34
|
```
|
|
50
35
|
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
```jsx
|
|
37
|
+
// src/main.jsx
|
|
38
|
+
import { app } from 'hyperapp'
|
|
39
|
+
|
|
40
|
+
const Increment = (state) => ({ count: state.count + 1 })
|
|
41
|
+
|
|
42
|
+
const view = (state) => (
|
|
43
|
+
<main id="app">
|
|
44
|
+
<button onclick={Increment}>Count: {state.count}</button>
|
|
45
|
+
</main>
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
const node = document.getElementById('app')
|
|
49
|
+
if (!node) throw new Error('Mount node not found')
|
|
53
50
|
|
|
51
|
+
app({
|
|
52
|
+
init: { count: 0 },
|
|
53
|
+
view,
|
|
54
|
+
node,
|
|
55
|
+
})
|
|
54
56
|
```
|
|
55
|
-
|
|
57
|
+
|
|
58
|
+
## Views in JSX or TSX
|
|
59
|
+
|
|
60
|
+
You are free to use hyperapp's built-in `h()` and `text()`, or `@hyperapp/html` or any other view authoring system you prefer.
|
|
61
|
+
|
|
62
|
+
But if you want to use JSX, you can do so with no extra config. Just make sure to name every file where you use JSX with the extension `.jsx` (or `.tsx` if you are using Typescript).
|
|
63
|
+
|
|
64
|
+
### Component children
|
|
65
|
+
|
|
66
|
+
Unlike the old standard, the JSX support of this plugin now follows the modern convention of putting `children` as a property of components, rather than a second argument.
|
|
67
|
+
|
|
68
|
+
```jsx
|
|
69
|
+
function Panel({ title, children }) {
|
|
70
|
+
return (
|
|
71
|
+
<section>
|
|
72
|
+
<h2>{title}</h2>
|
|
73
|
+
{children}
|
|
74
|
+
</section>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const view = (state) => (
|
|
79
|
+
<main id="app">
|
|
80
|
+
<Panel title="Welcome"><p>{state.message}</p></Panel>
|
|
81
|
+
</main>
|
|
82
|
+
)
|
|
56
83
|
```
|
|
84
|
+
### Fragments
|
|
57
85
|
|
|
58
|
-
|
|
86
|
+
The JSX support comes with support for fragments (`<>...</>`) - allowing components to return an array of nodes.
|
|
59
87
|
|
|
60
|
-
|
|
88
|
+
```jsx
|
|
61
89
|
|
|
62
|
-
|
|
90
|
+
function Items({items}) {
|
|
91
|
+
return (
|
|
92
|
+
<>
|
|
93
|
+
{items.map(txt => <li>{txt}</li>)}
|
|
94
|
+
</>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
63
97
|
|
|
64
|
-
|
|
65
|
-
|
|
98
|
+
function List({items}) {
|
|
99
|
+
return (
|
|
100
|
+
<ul>
|
|
101
|
+
<li>Always First</li>
|
|
102
|
+
<Items items={items} />
|
|
103
|
+
<li>Always Last</li>
|
|
104
|
+
</ul>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
66
107
|
|
|
67
|
-
|
|
108
|
+
<List items={['a', 'b', 'c']} />
|
|
109
|
+
/* ==>
|
|
110
|
+
<ul>
|
|
111
|
+
<li>Always First</li>
|
|
112
|
+
<li>a</li>
|
|
113
|
+
<li>b</li>
|
|
114
|
+
<li>c</li>
|
|
115
|
+
<li>Always Last</li>
|
|
116
|
+
</ul>
|
|
117
|
+
*/
|
|
118
|
+
```
|
|
68
119
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
120
|
+
> Note: Hyperapp requires the top node of the view to ***not*** be a fragment.
|
|
121
|
+
|
|
122
|
+
### Using TypeScript (TSX)
|
|
123
|
+
|
|
124
|
+
If you use TypeScript, use the file extension `.tsx` rather than `.jsx`.
|
|
125
|
+
|
|
126
|
+
You will also need to configure TypeScript to recognize the JSX runtime in your `tsconfig.json`, by adding the following to your `compilerOptions`:
|
|
127
|
+
|
|
128
|
+
```jsonc
|
|
129
|
+
// tsconfig.json
|
|
130
|
+
{
|
|
131
|
+
"compilerOptions": {
|
|
132
|
+
"jsx": "react-jsx",
|
|
133
|
+
"jsxImportSource": "vite-plugin-hyperapp/jsx"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
For components that accept children, type the children as `Child` – a convenience type exported from the runtime:
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import type { Child } from 'vite-plugin-hyperapp/jsx/jsx-runtime'
|
|
142
|
+
|
|
143
|
+
function Panel({ title, children }: { title: string; children?: Child }) {
|
|
144
|
+
return (
|
|
145
|
+
<section>
|
|
146
|
+
<h2>{title}</h2>
|
|
147
|
+
{children}
|
|
148
|
+
</section>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
76
151
|
```
|
|
77
152
|
|
|
78
|
-
|
|
153
|
+
## Hot module reloading
|
|
154
|
+
|
|
155
|
+
Hot Module Reloading is on by default in the dev server, when using this plugin. It means that any changes to your app will be reloaded *without clearing the state*. That lets you navigate to a particular view and develop it with live updates – and because the state does not change, you don't have to navigate back to the view to see your changes – you are already there!
|
|
156
|
+
|
|
157
|
+
For HMR to work, some simple rules need to be observed:
|
|
158
|
+
|
|
159
|
+
- In your main client side entry, import `app` from `hyperapp` *without renaming it* – e.g. do *not* `import {app as hyperApp} ...`
|
|
160
|
+
- Use an id to identify the app mountpoint in the html entrypoint, and make sure to use the exact same tag ***and id*** for the top vnode of your view.
|
|
161
|
+
- Any kind of logic you put outside of `app()` risks being rerun every HMR so keep your app logic contained to the properties you pass to app (`init`, `subscriptions`, `dispatch`).
|
|
162
|
+
|
|
163
|
+
If HMR is giving you grief, simply disable it by setting the `hmr` option to `false` in the plugin options:
|
|
164
|
+
|
|
79
165
|
|
|
80
166
|
```js
|
|
81
|
-
//vite.config.js
|
|
167
|
+
// vite.config.js
|
|
168
|
+
import { defineConfig } from 'vite'
|
|
169
|
+
import { hyperapp } from 'vite-plugin-hyperapp'
|
|
170
|
+
|
|
82
171
|
export default defineConfig({
|
|
83
172
|
plugins: [hyperapp({
|
|
84
173
|
hmr: false
|
|
@@ -86,116 +175,179 @@ export default defineConfig({
|
|
|
86
175
|
})
|
|
87
176
|
```
|
|
88
177
|
|
|
89
|
-
## Server-side Rendering (SSR)
|
|
90
178
|
|
|
91
|
-
Server
|
|
179
|
+
## Server-side rendering
|
|
180
|
+
|
|
181
|
+
Server-side rendering is when the server sends your app's initial view already fully rendered as HTML. Since Hyperapp recycles existing nodes (as long as they match the initial view), your initial view will be rendered even while your app is still loading, improving perceived performance.
|
|
182
|
+
|
|
183
|
+
See [Vite's SSR guide](https://vite.dev/guide/ssr) for setting up a server and
|
|
184
|
+
client entry.
|
|
92
185
|
|
|
93
|
-
|
|
186
|
+
This plugin exports `renderToString` from
|
|
187
|
+
`vite-plugin-hyperapp/ssr`. Import it in your server entry to render the
|
|
188
|
+
initial view to an HTML string:
|
|
94
189
|
|
|
95
|
-
|
|
190
|
+
```js
|
|
191
|
+
// src/entry-server.js
|
|
192
|
+
import { renderToString } from 'vite-plugin-hyperapp/ssr'
|
|
193
|
+
import { init, view } from './app.jsx'
|
|
194
|
+
|
|
195
|
+
//...
|
|
196
|
+
|
|
197
|
+
let html = readFileSync('./index.html.template', 'utf-8')
|
|
198
|
+
html = html.replace(
|
|
199
|
+
'<!--ssr-outlet-->,
|
|
200
|
+
() => renderToString({init, view })
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
//... respond with html
|
|
204
|
+
|
|
205
|
+
```
|
|
96
206
|
|
|
97
|
-
|
|
207
|
+
### How to avoid calling browser APIs server-side
|
|
98
208
|
|
|
99
|
-
|
|
209
|
+
Since you pass the same `init` to your server rendering as you pass to your client side app (in order to get the same initial view), there is a danger if your init runs effects that depend on browser-only APIs.
|
|
210
|
+
|
|
211
|
+
To avoid this, use the `import.meta.env.SSR` environment variable in your init action, to opt out of browser-only effects when in SSR:
|
|
100
212
|
|
|
101
213
|
```js
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
214
|
+
// src/app.jsx
|
|
215
|
+
const focusInput = () => document.querySelector('#new-item')?.focus()
|
|
216
|
+
|
|
217
|
+
export const init = () => [
|
|
218
|
+
{items: []},
|
|
219
|
+
!import.meta.env.SSR && focusInput //effect won't run in SSR
|
|
220
|
+
]
|
|
107
221
|
```
|
|
108
222
|
|
|
109
|
-
|
|
223
|
+
> Note: this only matters for the init action. renderToString does not run subscriptions, nor other actions - unless an init effect dispatches them.
|
|
110
224
|
|
|
111
|
-
> It is important that the server-entry module has `import ... from 'vite-plugin-hyperapp/ssr'` somewhere in it, in order for HMR to continue working on SSR enabled apps.
|
|
112
225
|
|
|
113
|
-
###
|
|
226
|
+
### Initializing your app with data
|
|
114
227
|
|
|
115
|
-
|
|
228
|
+
A common requirement is to initialize one's app with some preloaded data. Let's say, for example, you have a shopping cart and want to start the app with the cart items for the logged in user.
|
|
116
229
|
|
|
117
|
-
|
|
230
|
+
```js
|
|
231
|
+
//src/entry-server.js
|
|
232
|
+
|
|
233
|
+
// check auth header and get the logged in user
|
|
234
|
+
const user = await auth.checkLogin()
|
|
235
|
+
|
|
236
|
+
// get the users existing cart items:
|
|
237
|
+
const cartItems = await db.getCartItemsForUser(user)
|
|
238
|
+
|
|
239
|
+
// ... now, how do we send this data, along with the app
|
|
240
|
+
// to the client?
|
|
118
241
|
|
|
119
|
-
```html
|
|
120
|
-
<p>Static html here</p>
|
|
121
|
-
<div id="app"></div>
|
|
122
|
-
<p>More static html</p>
|
|
123
242
|
```
|
|
124
243
|
|
|
125
|
-
and
|
|
244
|
+
In order to ensure that the server and client both produce the same initial DOM structure, we must ensure they are initialized the same way with the same data. Here is a simple pattern for that:
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
#### Step 1 – Make the init action accept initialization data.
|
|
126
248
|
|
|
127
249
|
```js
|
|
128
|
-
app
|
|
129
|
-
|
|
130
|
-
|
|
250
|
+
//app.jsx
|
|
251
|
+
export const init = (
|
|
252
|
+
_,
|
|
253
|
+
{user, cartItems}={user:null, cartItems:[]}
|
|
254
|
+
) => ({
|
|
255
|
+
//...a bunch of other initial state,
|
|
256
|
+
cartItems, user
|
|
131
257
|
})
|
|
132
258
|
```
|
|
133
259
|
|
|
134
|
-
|
|
260
|
+
#### Step 2 - Pass the data as payload to init on the server
|
|
135
261
|
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
<!--ssr-outlet-->
|
|
140
|
-
</div>
|
|
141
|
-
<p>More static html</p>
|
|
142
|
-
```
|
|
262
|
+
```js
|
|
263
|
+
// src/entry-server.js
|
|
264
|
+
// ...
|
|
143
265
|
|
|
144
|
-
|
|
266
|
+
let html = readFileSync('./index.html.template', 'utf-8')
|
|
145
267
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
268
|
+
html = html.replace(
|
|
269
|
+
'<!--ssr-outlet-->',
|
|
270
|
+
() => renderToString({init: [init, {user, cartItems}], view })
|
|
271
|
+
)
|
|
150
272
|
```
|
|
151
273
|
|
|
152
|
-
|
|
153
|
-
|
|
274
|
+
#### Step 3 - Serialize the data into the html response
|
|
154
275
|
|
|
155
|
-
|
|
276
|
+
This way the same data will be available in the client when the app starts up.
|
|
156
277
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
278
|
+
```js
|
|
279
|
+
// src/entry-server.js
|
|
280
|
+
|
|
281
|
+
//...
|
|
282
|
+
|
|
283
|
+
//html-safe json serialization
|
|
284
|
+
const json = JSON
|
|
285
|
+
.stringify({user, cartItems})
|
|
286
|
+
.replace(
|
|
287
|
+
/[<>&\u2028\u2029]/g,
|
|
288
|
+
character => ({
|
|
289
|
+
'<': '\\u003c',
|
|
290
|
+
'>': '\\u003e',
|
|
291
|
+
'&': '\\u0026',
|
|
292
|
+
'\u2028': '\\u2028',
|
|
293
|
+
'\u2029': '\\u2029',
|
|
294
|
+
})[character]
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
html = html.replace(
|
|
298
|
+
'<!--initial-data-->',
|
|
299
|
+
() => `<script>window.initialData=${json};</script>`
|
|
300
|
+
)
|
|
301
|
+
```
|
|
160
302
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
303
|
+
(The HTML template might look like this)
|
|
304
|
+
```html
|
|
305
|
+
<!doctype html>
|
|
306
|
+
<html lang="en">
|
|
307
|
+
<head>
|
|
308
|
+
<meta charset="UTF-8" />
|
|
309
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
310
|
+
<title></title>
|
|
311
|
+
</head>
|
|
312
|
+
<body>
|
|
313
|
+
<!--initial-data-->
|
|
314
|
+
<!--ssr-outlet-->
|
|
315
|
+
<script type="module" src="/src/entry-client.js"></script>
|
|
316
|
+
</body>
|
|
317
|
+
</html>
|
|
164
318
|
|
|
165
|
-
export const view = (state:State) => (
|
|
166
|
-
<main id="app">
|
|
167
|
-
...
|
|
168
|
-
</main>
|
|
169
|
-
) as VNode<State>
|
|
170
319
|
```
|
|
171
320
|
|
|
172
|
-
### JSX/TSX children
|
|
173
321
|
|
|
174
|
-
|
|
322
|
+
#### Step 4 - Use the initial data in client app init
|
|
175
323
|
|
|
176
|
-
|
|
177
|
-
<MyComponent>
|
|
178
|
-
<p>foo</p>
|
|
179
|
-
<p>bar</p>
|
|
180
|
-
</MyComponent>
|
|
181
|
-
```
|
|
324
|
+
Wherever you start up your app in the client (in this example `entry-client.js`), pass along the data embedded in the page.
|
|
182
325
|
|
|
183
|
-
|
|
326
|
+
```js
|
|
327
|
+
// src/entry-client.js
|
|
328
|
+
import {app} from 'hyperapp'
|
|
329
|
+
import {init, view} from './app.jsx'
|
|
330
|
+
app({
|
|
331
|
+
init: [init, window.initialData],
|
|
332
|
+
view,
|
|
333
|
+
node: document.getElementById('app')
|
|
334
|
+
})
|
|
184
335
|
|
|
185
|
-
```jsx
|
|
186
|
-
const MyComponent = (props, children) => {
|
|
187
|
-
//children will be: [<p>foo</p>, <p>bar</p>]
|
|
188
|
-
}
|
|
189
336
|
```
|
|
190
337
|
|
|
191
|
-
|
|
338
|
+
## Safari TSX source maps
|
|
192
339
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
)
|
|
340
|
+
If Safari Web Inspector doesn't show your original TSX under the transformed
|
|
341
|
+
module, enable the optional development workaround:
|
|
342
|
+
|
|
343
|
+
```js
|
|
344
|
+
// vite.config.js
|
|
345
|
+
export default defineConfig({
|
|
346
|
+
plugins: [hyperapp({ safariExternalSourcemaps: true })],
|
|
347
|
+
})
|
|
200
348
|
```
|
|
201
349
|
|
|
350
|
+
It makes Safari load Vite's external `.tsx.map` rather than an inline map.
|
|
351
|
+
Safari shows the generated JS as the parent source and the original TSX below
|
|
352
|
+
it. Chrome and production output are unchanged. This option is off by default;
|
|
353
|
+
ordinary `.ts` files don't need it.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Development-only browser runtime. Keep this independent of any particular app.
|
|
2
|
+
const stateKey = '__hyperappHmrState';
|
|
3
|
+
export function createHmrApp(hot) {
|
|
4
|
+
let dispatch;
|
|
5
|
+
return {
|
|
6
|
+
mount(app, props) {
|
|
7
|
+
dispatch = app({
|
|
8
|
+
...props,
|
|
9
|
+
init: Object.hasOwn(hot.data, stateKey) ? hot.data[stateKey] : props.init,
|
|
10
|
+
});
|
|
11
|
+
return dispatch;
|
|
12
|
+
},
|
|
13
|
+
async dispose(data) {
|
|
14
|
+
// Let any already queued Hyperapp render finish before stopping the app.
|
|
15
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
16
|
+
dispatch(state => (data[stateKey] = state));
|
|
17
|
+
dispatch();
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../hmr/runtime.js"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,QAAQ,GAAG,oBAAoB,CAAA;AAErC,MAAM,UAAU,YAAY,CAAC,GAAG;IAC9B,IAAI,QAAQ,CAAA;IAEZ,OAAO;QACL,KAAK,CAAC,GAAG,EAAE,KAAK;YACd,QAAQ,GAAG,GAAG,CAAC;gBACb,GAAG,KAAK;gBACR,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;aAC1E,CAAC,CAAA;YACF,OAAO,QAAQ,CAAA;QACjB,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,IAAI;YAChB,yEAAyE;YACzE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAA;YAC5D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,CAAC,CAAA;YAC3C,QAAQ,EAAE,CAAA;QACZ,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["// Development-only browser runtime. Keep this independent of any particular app.\nconst stateKey = '__hyperappHmrState'\n\nexport function createHmrApp(hot) {\n let dispatch\n\n return {\n mount(app, props) {\n dispatch = app({\n ...props,\n init: Object.hasOwn(hot.data, stateKey) ? hot.data[stateKey] : props.init,\n })\n return dispatch\n },\n async dispose(data) {\n // Let any already queued Hyperapp render finish before stopping the app.\n await new Promise(resolve => requestAnimationFrame(resolve))\n dispatch(state => (data[stateKey] = state))\n dispatch()\n },\n }\n}\n"]}
|
package/dist/hmr/vite.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import MagicString from 'magic-string';
|
|
3
|
+
import { parseSync } from 'vite';
|
|
4
|
+
const virtualId = 'virtual:hyperapp-hmr';
|
|
5
|
+
const resolvedId = '\0' + virtualId;
|
|
6
|
+
// This plugin only instruments the module that imports and calls Hyperapp's app.
|
|
7
|
+
// It does not need to know the entry point, the app's state type, or its view.
|
|
8
|
+
export function hyperappHmr() {
|
|
9
|
+
return {
|
|
10
|
+
name: 'local:hyperapp-hmr',
|
|
11
|
+
apply: 'serve',
|
|
12
|
+
enforce: 'post', // inspect JavaScript after Vite has transformed TS/TSX
|
|
13
|
+
resolveId(id) {
|
|
14
|
+
if (id === virtualId)
|
|
15
|
+
return resolvedId;
|
|
16
|
+
},
|
|
17
|
+
async load(id) {
|
|
18
|
+
if (id === resolvedId) {
|
|
19
|
+
return readFile(new URL('./runtime.js', import.meta.url), 'utf8');
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
transform(code, id, options) {
|
|
23
|
+
if (options?.ssr || id.includes('/node_modules/') || !/\.[cm]?[jt]sx?(?:\?|$)/.test(id))
|
|
24
|
+
return;
|
|
25
|
+
if (!code.includes('hyperapp'))
|
|
26
|
+
return;
|
|
27
|
+
const ast = parseSync(id, code);
|
|
28
|
+
const importsApp = ast.program.body.some(node => node.type === 'ImportDeclaration' &&
|
|
29
|
+
node.source.value === 'hyperapp' &&
|
|
30
|
+
node.specifiers.some(specifier => specifier.type === 'ImportSpecifier' &&
|
|
31
|
+
specifier.imported.type === 'Identifier' &&
|
|
32
|
+
specifier.imported.name === 'app' &&
|
|
33
|
+
specifier.local.name === 'app'));
|
|
34
|
+
if (!importsApp)
|
|
35
|
+
return;
|
|
36
|
+
const calls = [];
|
|
37
|
+
function visit(value) {
|
|
38
|
+
if (!value || typeof value !== 'object')
|
|
39
|
+
return;
|
|
40
|
+
if (Array.isArray(value)) {
|
|
41
|
+
value.forEach(visit);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const node = value;
|
|
45
|
+
if (node.type === 'CallExpression') {
|
|
46
|
+
const callee = node.callee;
|
|
47
|
+
if (callee.type === 'Identifier' && callee.name === 'app') {
|
|
48
|
+
calls.push({ start: callee.start, end: callee.end });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const [key, child] of Object.entries(node)) {
|
|
52
|
+
if (key !== 'start' && key !== 'end')
|
|
53
|
+
visit(child);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
visit(ast.program.body);
|
|
57
|
+
if (!calls.length)
|
|
58
|
+
return;
|
|
59
|
+
if (calls.length !== 1) {
|
|
60
|
+
this.error(`Expected exactly one Hyperapp app() call in ${id}; found ${calls.length}`);
|
|
61
|
+
}
|
|
62
|
+
const output = new MagicString(code);
|
|
63
|
+
output.prepend(`import { createHmrApp as __hyperappHmrCreate } from '${virtualId}';\n` +
|
|
64
|
+
`const __hyperappHmr = __hyperappHmrCreate(import.meta.hot);\n`);
|
|
65
|
+
output.overwrite(calls[0].start, code.indexOf('(', calls[0].end) + 1, '__hyperappHmr.mount(app, ');
|
|
66
|
+
output.append('\nimport.meta.hot.accept();\nimport.meta.hot.dispose(__hyperappHmr.dispose);\n');
|
|
67
|
+
return { code: output.toString(), map: output.generateMap({ hires: true }) };
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=vite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","sourceRoot":"","sources":["../../hmr/vite.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile } from 'node:fs/promises'\nimport MagicString from 'magic-string'\nimport { parseSync, type Plugin } from 'vite'\n\nconst virtualId = 'virtual:hyperapp-hmr'\nconst resolvedId = '\\0' + virtualId\n\n// This plugin only instruments the module that imports and calls Hyperapp's app.\n// It does not need to know the entry point, the app's state type, or its view.\nexport function hyperappHmr(): Plugin {\n return {\n name: 'local:hyperapp-hmr',\n apply: 'serve',\n enforce: 'post', // inspect JavaScript after Vite has transformed TS/TSX\n resolveId(id) {\n if (id === virtualId) return resolvedId\n },\n async load(id) {\n if (id === resolvedId) {\n return readFile(new URL('./runtime.js', import.meta.url), 'utf8')\n }\n },\n transform(code, id, options) {\n if (options?.ssr || id.includes('/node_modules/') || !/\\.[cm]?[jt]sx?(?:\\?|$)/.test(id)) return\n if (!code.includes('hyperapp')) return\n\n const ast = parseSync(id, code)\n const importsApp = ast.program.body.some(node =>\n node.type === 'ImportDeclaration' &&\n node.source.value === 'hyperapp' &&\n node.specifiers.some(specifier =>\n specifier.type === 'ImportSpecifier' &&\n specifier.imported.type === 'Identifier' &&\n specifier.imported.name === 'app' &&\n specifier.local.name === 'app',\n ),\n )\n if (!importsApp) return\n\n const calls: { start: number; end: number }[] = []\n function visit(value: unknown): void {\n if (!value || typeof value !== 'object') return\n if (Array.isArray(value)) {\n value.forEach(visit)\n return\n }\n const node = value as Record<string, unknown>\n if (node.type === 'CallExpression') {\n const callee = node.callee as { type: string; name?: string; start: number; end: number }\n if (callee.type === 'Identifier' && callee.name === 'app') {\n calls.push({ start: callee.start, end: callee.end })\n }\n }\n for (const [key, child] of Object.entries(node)) {\n if (key !== 'start' && key !== 'end') visit(child)\n }\n }\n visit(ast.program.body)\n if (!calls.length) return\n if (calls.length !== 1) {\n this.error(`Expected exactly one Hyperapp app() call in ${id}; found ${calls.length}`)\n }\n\n const output = new MagicString(code)\n output.prepend(\n `import { createHmrApp as __hyperappHmrCreate } from '${virtualId}';\\n` +\n `const __hyperappHmr = __hyperappHmrCreate(import.meta.hot);\\n`,\n )\n output.overwrite(\n calls[0].start,\n code.indexOf('(', calls[0].end) + 1,\n '__hyperappHmr.mount(app, ',\n )\n output.append('\\nimport.meta.hot.accept();\\nimport.meta.hot.dispose(__hyperappHmr.dispose);\\n')\n return { code: output.toString(), map: output.generateMap({ hires: true }) }\n },\n }\n}\n"]}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { hyperappJsx } from './jsx/vite.js';
|
|
2
|
+
import { hyperappHmr } from './hmr/vite.js';
|
|
3
|
+
import { safariExternalSourcemapsPlugin } from './safari-sourcemaps/vite.js';
|
|
4
|
+
export function hyperapp(options = {}) {
|
|
5
|
+
const plugins = [hyperappJsx()];
|
|
6
|
+
if (options.hmr !== false)
|
|
7
|
+
plugins.push(hyperappHmr());
|
|
8
|
+
if (options.safariExternalSourcemaps)
|
|
9
|
+
plugins.push(safariExternalSourcemapsPlugin());
|
|
10
|
+
return plugins;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAA;AAO5E,MAAM,UAAU,QAAQ,CAAC,OAAO,GAAoB,EAAE;IACpD,MAAM,OAAO,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;IAC/B,IAAI,OAAO,CAAC,GAAG,KAAK,KAAK;QAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;IACtD,IAAI,OAAO,CAAC,wBAAwB;QAAE,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,CAAC,CAAA;IACpF,OAAO,OAAO,CAAA;AAChB,CAAC","sourcesContent":["import type { Plugin } from 'vite'\nimport { hyperappJsx } from './jsx/vite.ts'\nimport { hyperappHmr } from './hmr/vite.ts'\nimport { safariExternalSourcemapsPlugin } from './safari-sourcemaps/vite.ts'\n\nexport type HyperappOptions = {\n hmr?: boolean\n safariExternalSourcemaps?: boolean\n}\n\nexport function hyperapp(options: HyperappOptions = {}): Plugin[] {\n const plugins = [hyperappJsx()]\n if (options.hmr !== false) plugins.push(hyperappHmr())\n if (options.safariExternalSourcemaps) plugins.push(safariExternalSourcemapsPlugin())\n return plugins\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-dev-runtime.js","sourceRoot":"","sources":["../../jsx/jsx-dev-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAY,MAAM,kBAAkB,CAAA;AAChE,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAEtC,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA","sourcesContent":["export { Fragment, jsx, jsxs, type JSX } from './jsx-runtime.ts'\nimport { jsx } from './jsx-runtime.ts'\n\nexport const jsxDEV = jsx\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Props, type VNode } from 'hyperapp';
|
|
2
|
+
export declare namespace JSX {
|
|
3
|
+
type Element = VNode<any>;
|
|
4
|
+
interface ElementChildrenAttribute {
|
|
5
|
+
children: {};
|
|
6
|
+
}
|
|
7
|
+
interface IntrinsicElements {
|
|
8
|
+
[tag: string]: Props<any> & {
|
|
9
|
+
children?: Child;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export type Child = JSX.Element | string | number | boolean | null | undefined | readonly Child[];
|
|
14
|
+
type Component = (props: Record<string, unknown>) => Child;
|
|
15
|
+
export declare const Fragment: (props: {
|
|
16
|
+
children?: Child;
|
|
17
|
+
}) => string | number | boolean | readonly Child[] | JSX.Element;
|
|
18
|
+
export declare function jsx(tag: string | Component, props: Record<string, any> | null, key?: string): JSX.Element;
|
|
19
|
+
export declare const jsxs: typeof jsx;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { h, text } from 'hyperapp';
|
|
2
|
+
export const Fragment = (props) => props.children ?? [];
|
|
3
|
+
function normalize(children) {
|
|
4
|
+
const result = [];
|
|
5
|
+
const visit = (child) => {
|
|
6
|
+
if (Array.isArray(child)) {
|
|
7
|
+
for (const item of child)
|
|
8
|
+
visit(item);
|
|
9
|
+
}
|
|
10
|
+
else if (typeof child === 'string' || typeof child === 'number') {
|
|
11
|
+
result.push(text(child));
|
|
12
|
+
}
|
|
13
|
+
else if (child != null && child !== false && child !== true) {
|
|
14
|
+
result.push(child);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
visit(children);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
export function jsx(tag, props, key) {
|
|
21
|
+
const attributes = props ?? {};
|
|
22
|
+
if (typeof tag === 'function')
|
|
23
|
+
return tag(attributes);
|
|
24
|
+
const { children, ...rest } = attributes;
|
|
25
|
+
return h(tag, key === undefined ? rest : { ...rest, key }, normalize(children));
|
|
26
|
+
}
|
|
27
|
+
export const jsxs = jsx;
|
|
28
|
+
//# sourceMappingURL=jsx-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-runtime.js","sourceRoot":"","sources":["../../jsx/jsx-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,IAAI,EAA0B,MAAM,UAAU,CAAA;AAgB1D,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAA2B,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAA;AAE7E,SAAS,SAAS,CAAC,QAAe;IAChC,MAAM,MAAM,GAAU,EAAE,CAAA;IACxB,MAAM,KAAK,GAAG,CAAC,KAAY,EAAQ,EAAE;QACnC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,MAAM,IAAI,IAAI,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QACvC,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;QAC1B,CAAC;aAAM,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC9D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpB,CAAC;IACH,CAAC,CAAA;IACD,KAAK,CAAC,QAAQ,CAAC,CAAA;IACf,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,GAAG,CACjB,GAAuB,EACvB,KAAiC,EACjC,GAAY;IAEZ,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE,CAAA;IAC9B,IAAI,OAAO,GAAG,KAAK,UAAU;QAAE,OAAO,GAAG,CAAC,UAAU,CAAgB,CAAA;IACpE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,UAAU,CAAA;IACxC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAA;AACjF,CAAC;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,CAAA","sourcesContent":["import { h, text, type Props, type VNode } from 'hyperapp'\n\n// JSX does not carry Hyperapp's application state type through the tree.\nexport namespace JSX {\n export type Element = VNode<any>\n export interface ElementChildrenAttribute {\n children: {}\n }\n export interface IntrinsicElements {\n [tag: string]: Props<any> & { children?: Child }\n }\n}\n\nexport type Child = JSX.Element | string | number | boolean | null | undefined | readonly Child[]\ntype Component = (props: Record<string, unknown>) => Child\n\nexport const Fragment = (props: { children?: Child }) => props.children ?? []\n\nfunction normalize(children: Child): any[] {\n const result: any[] = []\n const visit = (child: Child): void => {\n if (Array.isArray(child)) {\n for (const item of child) visit(item)\n } else if (typeof child === 'string' || typeof child === 'number') {\n result.push(text(child))\n } else if (child != null && child !== false && child !== true) {\n result.push(child)\n }\n }\n visit(children)\n return result\n}\n\nexport function jsx(\n tag: string | Component,\n props: Record<string, any> | null,\n key?: string,\n): JSX.Element {\n const attributes = props ?? {}\n if (typeof tag === 'function') return tag(attributes) as JSX.Element\n const { children, ...rest } = attributes\n return h(tag, key === undefined ? rest : { ...rest, key }, normalize(children))\n}\n\nexport const jsxs = jsx\n"]}
|
package/dist/jsx/vite.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
// The JSX import source points at this folder's standard automatic runtime files.
|
|
3
|
+
export function hyperappJsx() {
|
|
4
|
+
return {
|
|
5
|
+
name: 'local:hyperapp-jsx',
|
|
6
|
+
config() {
|
|
7
|
+
return {
|
|
8
|
+
oxc: {
|
|
9
|
+
jsx: { runtime: 'automatic', importSource: 'vite-plugin-hyperapp/jsx' },
|
|
10
|
+
},
|
|
11
|
+
resolve: {
|
|
12
|
+
alias: {
|
|
13
|
+
'vite-plugin-hyperapp/jsx': fileURLToPath(new URL('.', import.meta.url)),
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=vite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","sourceRoot":"","sources":["../../jsx/vite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAGxC,kFAAkF;AAClF,MAAM,UAAU,WAAW;IACzB,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,MAAM;YACJ,OAAO;gBACL,GAAG,EAAE;oBACH,GAAG,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,0BAA0B,EAAE;iBACxE;gBACD,OAAO,EAAE;oBACP,KAAK,EAAE;wBACL,0BAA0B,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;qBACzE;iBACF;aACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["import { fileURLToPath } from 'node:url'\nimport type { Plugin } from 'vite'\n\n// The JSX import source points at this folder's standard automatic runtime files.\nexport function hyperappJsx(): Plugin {\n return {\n name: 'local:hyperapp-jsx',\n config() {\n return {\n oxc: {\n jsx: { runtime: 'automatic', importSource: 'vite-plugin-hyperapp/jsx' },\n },\n resolve: {\n alias: {\n 'vite-plugin-hyperapp/jsx': fileURLToPath(new URL('.', import.meta.url)),\n },\n },\n }\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Safari Web Inspector needs an external map to show the original TSX source.
|
|
2
|
+
// Vite already serves .tsx.map requests; only the JS response needs changing.
|
|
3
|
+
export function safariExternalSourcemapsPlugin() {
|
|
4
|
+
return {
|
|
5
|
+
name: 'local:safari-external-sourcemaps',
|
|
6
|
+
apply: 'serve',
|
|
7
|
+
configureServer(server) {
|
|
8
|
+
server.middlewares.use((req, res, next) => {
|
|
9
|
+
const agent = req.headers['user-agent'] ?? '';
|
|
10
|
+
if (!/Safari\//.test(agent) || /Chrome\/|Chromium\/|CriOS\/|Edg\/|OPR\//.test(agent)) {
|
|
11
|
+
return next();
|
|
12
|
+
}
|
|
13
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
14
|
+
if (!url.pathname.endsWith('.tsx'))
|
|
15
|
+
return next();
|
|
16
|
+
delete req.headers['if-none-match'];
|
|
17
|
+
const end = res.end.bind(res);
|
|
18
|
+
const finish = (chunk, encoding, callback) => encoding ? end(chunk, encoding, callback) : callback ? end(chunk, callback) : end(chunk);
|
|
19
|
+
res.end = ((chunk, encoding, callback) => {
|
|
20
|
+
if (res.statusCode !== 200 || typeof chunk !== 'string') {
|
|
21
|
+
return finish(chunk, encoding, callback);
|
|
22
|
+
}
|
|
23
|
+
const rewritten = chunk.replace(/\/\/# sourceMappingURL=data:application\/json;base64,[A-Za-z0-9+/=]+\s*$/, `//# sourceMappingURL=${url.pathname}.map${url.search}`);
|
|
24
|
+
if (rewritten !== chunk)
|
|
25
|
+
res.removeHeader('ETag');
|
|
26
|
+
return finish(rewritten, encoding, callback);
|
|
27
|
+
});
|
|
28
|
+
next();
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=vite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","sourceRoot":"","sources":["../../safari-sourcemaps/vite.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,8EAA8E;AAC9E,MAAM,UAAU,8BAA8B;IAC5C,OAAO;QACL,IAAI,EAAE,kCAAkC;QACxC,KAAK,EAAE,OAAO;QACd,eAAe,CAAC,MAAM;YACpB,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;gBACxC,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAA;gBAC7C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,yCAAyC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBACrF,OAAO,IAAI,EAAE,CAAA;gBACf,CAAC;gBAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC,CAAA;gBAChF,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAAE,OAAO,IAAI,EAAE,CAAA;gBAEjD,OAAO,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;gBACnC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBAC7B,MAAM,MAAM,GAAG,CAAC,KAA2B,EAAE,QAAyB,EAAE,QAAqB,EAAE,EAAE,CAC/F,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;gBAC1F,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,KAA2B,EAAE,QAAyB,EAAE,QAAqB,EAAE,EAAE;oBAC3F,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;wBACxD,OAAO,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;oBAC1C,CAAC;oBACD,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAC7B,0EAA0E,EAC1E,wBAAwB,GAAG,CAAC,QAAQ,OAAO,GAAG,CAAC,MAAM,EAAE,CACxD,CAAA;oBACD,IAAI,SAAS,KAAK,KAAK;wBAAE,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;oBACjD,OAAO,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;gBAC9C,CAAC,CAAmB,CAAA;gBACpB,IAAI,EAAE,CAAA;YACR,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["import type { Plugin } from 'vite'\n\n// Safari Web Inspector needs an external map to show the original TSX source.\n// Vite already serves .tsx.map requests; only the JS response needs changing.\nexport function safariExternalSourcemapsPlugin(): Plugin {\n return {\n name: 'local:safari-external-sourcemaps',\n apply: 'serve',\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const agent = req.headers['user-agent'] ?? ''\n if (!/Safari\\//.test(agent) || /Chrome\\/|Chromium\\/|CriOS\\/|Edg\\/|OPR\\//.test(agent)) {\n return next()\n }\n\n const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`)\n if (!url.pathname.endsWith('.tsx')) return next()\n\n delete req.headers['if-none-match']\n const end = res.end.bind(res)\n const finish = (chunk?: string | Uint8Array, encoding?: BufferEncoding, callback?: () => void) =>\n encoding ? end(chunk, encoding, callback) : callback ? end(chunk, callback) : end(chunk)\n res.end = ((chunk?: string | Uint8Array, encoding?: BufferEncoding, callback?: () => void) => {\n if (res.statusCode !== 200 || typeof chunk !== 'string') {\n return finish(chunk, encoding, callback)\n }\n const rewritten = chunk.replace(\n /\\/\\/# sourceMappingURL=data:application\\/json;base64,[A-Za-z0-9+/=]+\\s*$/,\n `//# sourceMappingURL=${url.pathname}.map${url.search}`,\n )\n if (rewritten !== chunk) res.removeHeader('ETag')\n return finish(rewritten, encoding, callback)\n }) as typeof res.end\n next()\n })\n },\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { renderToString } from './render-to-string.ts';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../ssr/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA","sourcesContent":["export { renderToString } from './render-to-string.ts'\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Dispatchable, type VNode } from 'hyperapp';
|
|
2
|
+
type ServerAppProps<S> = {
|
|
3
|
+
init: Dispatchable<S>;
|
|
4
|
+
view: (state: S) => VNode<S>;
|
|
5
|
+
};
|
|
6
|
+
/** Render the state reached by Hyperapp's synchronous initialization effects. */
|
|
7
|
+
export declare function renderToString<S>({ init, view }: ServerAppProps<S>): string;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { app } from 'hyperapp';
|
|
2
|
+
import { vdomToHtml } from './vdom-html.js';
|
|
3
|
+
/** Render the state reached by Hyperapp's synchronous initialization effects. */
|
|
4
|
+
export function renderToString({ init, view }) {
|
|
5
|
+
const dispatch = app({ init });
|
|
6
|
+
let state;
|
|
7
|
+
dispatch(current => (state = current));
|
|
8
|
+
return vdomToHtml(view(state));
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=render-to-string.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-to-string.js","sourceRoot":"","sources":["../../ssr/render-to-string.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAiC,MAAM,UAAU,CAAA;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAO3C,iFAAiF;AACjF,MAAM,UAAU,cAAc,CAAI,EAAE,IAAI,EAAE,IAAI,EAAqB;IACjE,MAAM,QAAQ,GAAG,GAAG,CAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACjC,IAAI,KAAS,CAAA;IACb,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAA;IACtC,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;AAChC,CAAC","sourcesContent":["import { app, type Dispatchable, type VNode } from 'hyperapp'\nimport { vdomToHtml } from './vdom-html.ts'\n\ntype ServerAppProps<S> = {\n init: Dispatchable<S>\n view: (state: S) => VNode<S>\n}\n\n/** Render the state reached by Hyperapp's synchronous initialization effects. */\nexport function renderToString<S>({ init, view }: ServerAppProps<S>): string {\n const dispatch = app<S>({ init })\n let state!: S\n dispatch(current => (state = current))\n return vdomToHtml(view(state))\n}\n"]}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const booleanAttributes = new Set([
|
|
2
|
+
'allowfullscreen', 'async', 'autofocus', 'autoplay', 'checked', 'controls',
|
|
3
|
+
'default', 'defer', 'disabled', 'disablepictureinpicture',
|
|
4
|
+
'disableremoteplayback', 'formnovalidate', 'hidden', 'inert', 'ismap',
|
|
5
|
+
'itemscope', 'loop', 'multiple', 'muted', 'nomodule', 'novalidate', 'open',
|
|
6
|
+
'playsinline', 'readonly', 'required', 'reversed', 'selected',
|
|
7
|
+
]);
|
|
8
|
+
const overloadedBooleanAttributes = new Set(['capture', 'download']);
|
|
9
|
+
const voidElements = new Set([
|
|
10
|
+
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link',
|
|
11
|
+
'meta', 'param', 'source', 'track', 'wbr',
|
|
12
|
+
]);
|
|
13
|
+
const propertyOnly = new Set([
|
|
14
|
+
'children', 'key', 'innerHTML', 'outerHTML', 'textContent', 'innerText',
|
|
15
|
+
'nodeValue', 'scrollTop', 'scrollLeft', 'offsetWidth', 'offsetHeight',
|
|
16
|
+
'clientWidth', 'clientHeight', 'files', 'labels',
|
|
17
|
+
'elements', 'options', 'selectedOptions', 'validity', 'validationMessage',
|
|
18
|
+
'willValidate', 'selectionStart', 'selectionEnd', 'selectionDirection',
|
|
19
|
+
'valueAsDate', 'valueAsNumber',
|
|
20
|
+
]);
|
|
21
|
+
function escapeHtml(value) {
|
|
22
|
+
return String(value).replace(/[&<>"']/g, character => ({
|
|
23
|
+
'&': '&', '<': '<', '>': '>', '"': '"', "'": ''',
|
|
24
|
+
})[character]);
|
|
25
|
+
}
|
|
26
|
+
function styleName(name) {
|
|
27
|
+
if (name.startsWith('--'))
|
|
28
|
+
return name;
|
|
29
|
+
if (name === 'cssFloat')
|
|
30
|
+
return 'float';
|
|
31
|
+
return name.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)
|
|
32
|
+
.replace(/^ms-/, '-ms-');
|
|
33
|
+
}
|
|
34
|
+
function serializeStyle(style) {
|
|
35
|
+
if (!style || typeof style !== 'object')
|
|
36
|
+
return '';
|
|
37
|
+
return Object.entries(style).flatMap(([name, value]) => value == null || value === '' || typeof value === 'boolean'
|
|
38
|
+
? []
|
|
39
|
+
: [`${styleName(name)}: ${String(value)}`]).join('; ');
|
|
40
|
+
}
|
|
41
|
+
function serializeProps(props, tag, isSvg) {
|
|
42
|
+
let attributes = '';
|
|
43
|
+
for (const [property, value] of Object.entries(props)) {
|
|
44
|
+
if (property.startsWith('on') || propertyOnly.has(property) || value == null)
|
|
45
|
+
continue;
|
|
46
|
+
if (property === 'style') {
|
|
47
|
+
const css = serializeStyle(value);
|
|
48
|
+
if (css)
|
|
49
|
+
attributes += ` style="${escapeHtml(css)}"`;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (typeof value === 'function' || typeof value === 'object' || typeof value === 'symbol')
|
|
53
|
+
continue;
|
|
54
|
+
// An input's current value is reflected by its value attribute; for a
|
|
55
|
+
// textarea, the initial value lives in its text content instead.
|
|
56
|
+
if ((tag === 'textarea' || tag === 'select') && (property === 'value' || property === 'defaultValue'))
|
|
57
|
+
continue;
|
|
58
|
+
if (property === 'defaultValue' && tag !== 'input')
|
|
59
|
+
continue;
|
|
60
|
+
if (property === 'defaultChecked' && tag !== 'input')
|
|
61
|
+
continue;
|
|
62
|
+
const name = property === 'defaultValue' ? 'value'
|
|
63
|
+
: property === 'defaultChecked' ? 'checked'
|
|
64
|
+
: isSvg ? property : property.toLowerCase();
|
|
65
|
+
if (!/^[^\s"'<>/=]+$/.test(name))
|
|
66
|
+
continue;
|
|
67
|
+
if (!isSvg && booleanAttributes.has(name)) {
|
|
68
|
+
if (value)
|
|
69
|
+
attributes += ` ${name}`;
|
|
70
|
+
}
|
|
71
|
+
else if (!isSvg && overloadedBooleanAttributes.has(name) && value === true) {
|
|
72
|
+
attributes += ` ${name}`;
|
|
73
|
+
}
|
|
74
|
+
else if (typeof value !== 'boolean' || name.startsWith('aria-') || name.startsWith('data-') ||
|
|
75
|
+
(!isSvg && ['contenteditable', 'draggable', 'spellcheck', 'translate'].includes(name))) {
|
|
76
|
+
attributes += ` ${name}="${escapeHtml(value)}"`;
|
|
77
|
+
}
|
|
78
|
+
else if (isSvg && value === true) {
|
|
79
|
+
attributes += ` ${name}="true"`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return attributes;
|
|
83
|
+
}
|
|
84
|
+
function render(node, isSvg) {
|
|
85
|
+
if (node == null || typeof node === 'boolean')
|
|
86
|
+
return '';
|
|
87
|
+
if (typeof node.tag === 'function')
|
|
88
|
+
return render(node.tag(node.memo), isSvg);
|
|
89
|
+
if (node.type === 3)
|
|
90
|
+
return escapeHtml(node.tag);
|
|
91
|
+
const tag = node.tag;
|
|
92
|
+
if (!/^[A-Za-z][\w:.-]*$/.test(tag))
|
|
93
|
+
throw new Error(`Invalid element tag: ${tag}`);
|
|
94
|
+
const svg = isSvg || tag === 'svg';
|
|
95
|
+
const props = node.props;
|
|
96
|
+
const attributes = serializeProps(props, tag, svg);
|
|
97
|
+
if (!svg && voidElements.has(tag))
|
|
98
|
+
return `<${tag}${attributes}>`;
|
|
99
|
+
let children;
|
|
100
|
+
if (tag === 'textarea' && !svg && (props.value != null || props.defaultValue != null)) {
|
|
101
|
+
children = escapeHtml(props.value ?? props.defaultValue);
|
|
102
|
+
}
|
|
103
|
+
else if ((tag === 'script' || tag === 'style') && !svg) {
|
|
104
|
+
// Raw-text HTML elements do not decode character references. A closing
|
|
105
|
+
// tag in the content cannot safely be represented as a text child.
|
|
106
|
+
children = node.children.map(child => {
|
|
107
|
+
if (child == null || typeof child === 'boolean')
|
|
108
|
+
return '';
|
|
109
|
+
if (child.type !== 3)
|
|
110
|
+
throw new Error(`${tag} only supports text children`);
|
|
111
|
+
const value = String(child.tag);
|
|
112
|
+
if (new RegExp(`</${tag}(?:[\\s/>])`, 'i').test(value)) {
|
|
113
|
+
throw new Error(`Cannot serialize a closing ${tag} tag inside its text`);
|
|
114
|
+
}
|
|
115
|
+
return value;
|
|
116
|
+
}).join('');
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
children = node.children.map(child => render(child, svg && tag !== 'foreignObject')).join('');
|
|
120
|
+
}
|
|
121
|
+
// The HTML parser discards the first newline after these opening tags.
|
|
122
|
+
if (!svg && ['pre', 'listing', 'textarea'].includes(tag) && children.startsWith('\n')) {
|
|
123
|
+
children = `\n${children}`;
|
|
124
|
+
}
|
|
125
|
+
return `<${tag}${attributes}>${children}</${tag}>`;
|
|
126
|
+
}
|
|
127
|
+
/** Serialize an existing Hyperapp virtual tree without starting an app or using the DOM. */
|
|
128
|
+
export function vdomToHtml(node) {
|
|
129
|
+
return render(node, false);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=vdom-html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vdom-html.js","sourceRoot":"","sources":["../../ssr/vdom-html.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ElementVNode, VNode } from 'hyperapp'\n\nconst booleanAttributes = new Set([\n 'allowfullscreen', 'async', 'autofocus', 'autoplay', 'checked', 'controls',\n 'default', 'defer', 'disabled', 'disablepictureinpicture',\n 'disableremoteplayback', 'formnovalidate', 'hidden', 'inert', 'ismap',\n 'itemscope', 'loop', 'multiple', 'muted', 'nomodule', 'novalidate', 'open',\n 'playsinline', 'readonly', 'required', 'reversed', 'selected',\n])\nconst overloadedBooleanAttributes = new Set(['capture', 'download'])\nconst voidElements = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link',\n 'meta', 'param', 'source', 'track', 'wbr',\n])\nconst propertyOnly = new Set([\n 'children', 'key', 'innerHTML', 'outerHTML', 'textContent', 'innerText',\n 'nodeValue', 'scrollTop', 'scrollLeft', 'offsetWidth', 'offsetHeight',\n 'clientWidth', 'clientHeight', 'files', 'labels',\n 'elements', 'options', 'selectedOptions', 'validity', 'validationMessage',\n 'willValidate', 'selectionStart', 'selectionEnd', 'selectionDirection',\n 'valueAsDate', 'valueAsNumber',\n])\n\nfunction escapeHtml(value: unknown): string {\n return String(value).replace(/[&<>\"']/g, character => ({\n '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''',\n })[character]!)\n}\n\nfunction styleName(name: string): string {\n if (name.startsWith('--')) return name\n if (name === 'cssFloat') return 'float'\n return name.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)\n .replace(/^ms-/, '-ms-')\n}\n\nfunction serializeStyle(style: unknown): string {\n if (!style || typeof style !== 'object') return ''\n return Object.entries(style).flatMap(([name, value]) =>\n value == null || value === '' || typeof value === 'boolean'\n ? []\n : [`${styleName(name)}: ${String(value)}`],\n ).join('; ')\n}\n\nfunction serializeProps(props: Record<string, unknown>, tag: string, isSvg: boolean): string {\n let attributes = ''\n for (const [property, value] of Object.entries(props)) {\n if (property.startsWith('on') || propertyOnly.has(property) || value == null) continue\n if (property === 'style') {\n const css = serializeStyle(value)\n if (css) attributes += ` style=\"${escapeHtml(css)}\"`\n continue\n }\n if (typeof value === 'function' || typeof value === 'object' || typeof value === 'symbol') continue\n\n // An input's current value is reflected by its value attribute; for a\n // textarea, the initial value lives in its text content instead.\n if ((tag === 'textarea' || tag === 'select') && (property === 'value' || property === 'defaultValue')) continue\n if (property === 'defaultValue' && tag !== 'input') continue\n if (property === 'defaultChecked' && tag !== 'input') continue\n\n const name = property === 'defaultValue' ? 'value'\n : property === 'defaultChecked' ? 'checked'\n : isSvg ? property : property.toLowerCase()\n\n if (!/^[^\\s\"'<>/=]+$/.test(name)) continue\n if (!isSvg && booleanAttributes.has(name)) {\n if (value) attributes += ` ${name}`\n } else if (!isSvg && overloadedBooleanAttributes.has(name) && value === true) {\n attributes += ` ${name}`\n } else if (typeof value !== 'boolean' || name.startsWith('aria-') || name.startsWith('data-') ||\n (!isSvg && ['contenteditable', 'draggable', 'spellcheck', 'translate'].includes(name))) {\n attributes += ` ${name}=\"${escapeHtml(value)}\"`\n } else if (isSvg && value === true) {\n attributes += ` ${name}=\"true\"`\n }\n }\n return attributes\n}\n\nfunction render(node: VNode<any> | boolean | null | undefined, isSvg: boolean): string {\n if (node == null || typeof node === 'boolean') return ''\n if (typeof node.tag === 'function') return render(node.tag((node as ElementVNode<any>).memo!), isSvg)\n if (node.type === 3) return escapeHtml(node.tag)\n\n const tag = node.tag\n if (!/^[A-Za-z][\\w:.-]*$/.test(tag)) throw new Error(`Invalid element tag: ${tag}`)\n const svg = isSvg || tag === 'svg'\n const props = node.props as Record<string, unknown>\n const attributes = serializeProps(props, tag, svg)\n if (!svg && voidElements.has(tag)) return `<${tag}${attributes}>`\n\n let children: string\n if (tag === 'textarea' && !svg && (props.value != null || props.defaultValue != null)) {\n children = escapeHtml(props.value ?? props.defaultValue)\n } else if ((tag === 'script' || tag === 'style') && !svg) {\n // Raw-text HTML elements do not decode character references. A closing\n // tag in the content cannot safely be represented as a text child.\n children = node.children.map(child => {\n if (child == null || typeof child === 'boolean') return ''\n if (child.type !== 3) throw new Error(`${tag} only supports text children`)\n const value = String(child.tag)\n if (new RegExp(`</${tag}(?:[\\\\s/>])`, 'i').test(value)) {\n throw new Error(`Cannot serialize a closing ${tag} tag inside its text`)\n }\n return value\n }).join('')\n } else {\n children = node.children.map(child => render(child, svg && tag !== 'foreignObject')).join('')\n }\n // The HTML parser discards the first newline after these opening tags.\n if (!svg && ['pre', 'listing', 'textarea'].includes(tag) && children.startsWith('\\n')) {\n children = `\\n${children}`\n }\n return `<${tag}${attributes}>${children}</${tag}>`\n}\n\n/** Serialize an existing Hyperapp virtual tree without starting an app or using the DOM. */\nexport function vdomToHtml(node: VNode<any>): string {\n return render(node, false)\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,51 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-hyperapp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Plugin and helpers for using Hyperapp with Vite",
|
|
6
|
-
"main": "./index.js",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
|
-
},
|
|
10
6
|
"author": "Zacharias Enochsson",
|
|
11
7
|
"license": "MIT",
|
|
12
|
-
"files": [
|
|
13
|
-
"*.js",
|
|
14
|
-
"*.d.ts"
|
|
15
|
-
],
|
|
16
8
|
"exports": {
|
|
17
9
|
".": {
|
|
18
|
-
"types": "./index.d.ts",
|
|
19
|
-
"import": "./index.js"
|
|
20
|
-
"default": "./index.js"
|
|
21
|
-
},
|
|
22
|
-
"./jsx": {
|
|
23
|
-
"types": "./jsx.d.ts",
|
|
24
|
-
"import": "./jsx.js",
|
|
25
|
-
"default": "./jsx.js"
|
|
26
|
-
},
|
|
27
|
-
"./jsx.js": {
|
|
28
|
-
"types": "./jsx.d.ts",
|
|
29
|
-
"import": "./jsx.js",
|
|
30
|
-
"default": "./jsx.js"
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
31
12
|
},
|
|
32
13
|
"./ssr": {
|
|
33
|
-
"types": "./ssr.d.ts",
|
|
34
|
-
"import": "./ssr.js"
|
|
35
|
-
"default": "./ssr.js"
|
|
14
|
+
"types": "./dist/ssr/index.d.ts",
|
|
15
|
+
"import": "./dist/ssr/index.js"
|
|
36
16
|
},
|
|
37
|
-
"./
|
|
38
|
-
"types": "./
|
|
39
|
-
"import": "./
|
|
40
|
-
|
|
17
|
+
"./jsx/jsx-runtime": {
|
|
18
|
+
"types": "./dist/jsx/jsx-runtime.d.ts",
|
|
19
|
+
"import": "./dist/jsx/jsx-runtime.js"
|
|
20
|
+
},
|
|
21
|
+
"./jsx/jsx-dev-runtime": {
|
|
22
|
+
"types": "./dist/jsx/jsx-dev-runtime.d.ts",
|
|
23
|
+
"import": "./dist/jsx/jsx-dev-runtime.js"
|
|
41
24
|
},
|
|
42
25
|
"./package.json": "./package.json"
|
|
43
26
|
},
|
|
27
|
+
"files": ["dist"],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc -p tsconfig.build.json",
|
|
30
|
+
"test": "npm run build && vitest run"
|
|
31
|
+
},
|
|
44
32
|
"dependencies": {
|
|
45
|
-
"
|
|
46
|
-
"hyperapp": "^2.0.22"
|
|
33
|
+
"magic-string": "^1.4.3"
|
|
47
34
|
},
|
|
48
35
|
"peerDependencies": {
|
|
49
|
-
"
|
|
36
|
+
"hyperapp": "^2.0.22",
|
|
37
|
+
"vite": "^8.3.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^26.6.5",
|
|
41
|
+
"hyperapp": "^2.0.22",
|
|
42
|
+
"typescript": "^7.0.2",
|
|
43
|
+
"vite": "^8.3.0",
|
|
44
|
+
"vitest": "^5.0.3"
|
|
50
45
|
}
|
|
51
46
|
}
|
package/index.d.ts
DELETED
package/index.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
const defaultOptions = {
|
|
2
|
-
hmr: true,
|
|
3
|
-
dispatchExport: "dispatch",
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
const rxIsEntry = /import {.*app[^}]*} from "hyperapp"/
|
|
7
|
-
const rxIsSSREntry = /import .+ from "vite-plugin-hyperapp\/ssr"/
|
|
8
|
-
|
|
9
|
-
const HMRAppendage = dispatch => `
|
|
10
|
-
if (import.meta.hot) {
|
|
11
|
-
import.meta.hot.accept(m => {
|
|
12
|
-
if (!${dispatch}) return
|
|
13
|
-
let prevState = null
|
|
14
|
-
${dispatch}(s => (prevState = s))
|
|
15
|
-
${dispatch}()
|
|
16
|
-
m.${dispatch}(prevState)
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
`
|
|
20
|
-
|
|
21
|
-
const SSRHMRAppendage = `
|
|
22
|
-
if (import.meta.hot) {
|
|
23
|
-
import.meta.hot.accept()
|
|
24
|
-
}
|
|
25
|
-
`
|
|
26
|
-
|
|
27
|
-
export default function injectConsoleLog(options = {}) {
|
|
28
|
-
options = { ...defaultOptions, ...options }
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
name: "vite-plugin-hyperapp",
|
|
32
|
-
|
|
33
|
-
config: () => ({
|
|
34
|
-
esbuild: {
|
|
35
|
-
jsxFactory: "jsx",
|
|
36
|
-
jsxFragment: "jsxFragment",
|
|
37
|
-
jsxInject:
|
|
38
|
-
"import {jsx, jsxFragment} from 'vite-plugin-hyperapp/jsx.js'",
|
|
39
|
-
},
|
|
40
|
-
}),
|
|
41
|
-
|
|
42
|
-
async transform(code, id) {
|
|
43
|
-
if (!options.hmr) return null
|
|
44
|
-
|
|
45
|
-
if (rxIsEntry.test(code)) {
|
|
46
|
-
return {
|
|
47
|
-
code: code + HMRAppendage(options.dispatchExport),
|
|
48
|
-
map: null,
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (rxIsSSREntry.test(code)) {
|
|
53
|
-
return {
|
|
54
|
-
code: code + SSRHMRAppendage,
|
|
55
|
-
map: null,
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return null
|
|
60
|
-
},
|
|
61
|
-
}
|
|
62
|
-
}
|
package/jsx.d.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { Props, MaybeVNode, ElementVNode } from "hyperapp"
|
|
2
|
-
|
|
3
|
-
type Component<S, P> = (
|
|
4
|
-
props: P,
|
|
5
|
-
children: MaybeVNode<S>[],
|
|
6
|
-
) => MaybeVNode<S> | MaybeVNode<S>[]
|
|
7
|
-
|
|
8
|
-
type _JSXChild<S> = string | number | MaybeVNode<S>
|
|
9
|
-
type JSXChild<S> = _JSXChild<S> | _JSXChild<S>[]
|
|
10
|
-
|
|
11
|
-
export declare function jsx<S>(
|
|
12
|
-
type: string,
|
|
13
|
-
props?: Props<S>,
|
|
14
|
-
...children: JSXChild<S>[]
|
|
15
|
-
): ElementVNode<S>
|
|
16
|
-
|
|
17
|
-
export declare function jsx<S, P>(
|
|
18
|
-
type: Component<S, P>,
|
|
19
|
-
props?: P | null,
|
|
20
|
-
...children: JSXChild<S>[]
|
|
21
|
-
): ReturnType<Component<S, P>>
|
|
22
|
-
|
|
23
|
-
export declare function jsxFragment<S>(
|
|
24
|
-
_: any,
|
|
25
|
-
children: JSXChild<S>[],
|
|
26
|
-
): MaybeVNode<S>[]
|
|
27
|
-
|
|
28
|
-
declare global {
|
|
29
|
-
namespace JSX {
|
|
30
|
-
/** Result of a JSX expression. Components may return arrays. */
|
|
31
|
-
type Element = MaybeVNode<any> | MaybeVNode<any>[]
|
|
32
|
-
|
|
33
|
-
/** What you can put in the `<X />` position */
|
|
34
|
-
type ElementType = string | Component<any, any>
|
|
35
|
-
|
|
36
|
-
/** Allow `<>...</>` fragments; returns an array */
|
|
37
|
-
type Fragment = MaybeVNode<any>[]
|
|
38
|
-
|
|
39
|
-
/** Intrinsic (HTML/SVG) elements. */
|
|
40
|
-
interface IntrinsicElements {
|
|
41
|
-
[elem: string]: Props<any>
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** prevents errors about children missing from props in components */
|
|
45
|
-
type LibraryManagedAttributes<P> = P & { children?: JSXChild<any>[] }
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// make jsx and jsxFragment ambient globals because
|
|
50
|
-
// ts server doesn't know I'll add them later in transform
|
|
51
|
-
type JsxFn = typeof jsx
|
|
52
|
-
type JsxFragmentFn = typeof jsxFragment
|
|
53
|
-
|
|
54
|
-
declare global {
|
|
55
|
-
const jsx: JsxFn
|
|
56
|
-
const jsxFragment: JsxFragmentFn
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export {}
|
package/jsx.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { h, text } from "hyperapp"
|
|
2
|
-
|
|
3
|
-
const cproc = children =>
|
|
4
|
-
children
|
|
5
|
-
.flat()
|
|
6
|
-
.map(x => ((typeof x === "string") | (typeof x === "number") ? text(x) : x))
|
|
7
|
-
|
|
8
|
-
export const jsx = (tag, props, ...children) =>
|
|
9
|
-
typeof tag === "function"
|
|
10
|
-
? tag(props, cproc(children))
|
|
11
|
-
: h(tag, props || {}, cproc(children))
|
|
12
|
-
|
|
13
|
-
export const jsxFragment = (_, children) => cproc(children)
|
package/ssr.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Subscription } from "hyperapp"
|
|
2
|
-
|
|
3
|
-
type Defs<S = any> = {
|
|
4
|
-
init?: Dispatchable<S>
|
|
5
|
-
view?: (state: S) => VNode<S>
|
|
6
|
-
subscriptions?: (state: S) => Subscription<S>[]
|
|
7
|
-
dispatch?: (d: Dispatch<S>) => Dispatch<S>
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
declare module "vite-plugin-hyperapp/ssr" {
|
|
11
|
-
export default function (defs: Defs): Promise<string>
|
|
12
|
-
}
|
package/ssr.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { JSDOM } from "jsdom"
|
|
2
|
-
import { app } from "hyperapp"
|
|
3
|
-
|
|
4
|
-
export default function (defs) {
|
|
5
|
-
const dom = new JSDOM("")
|
|
6
|
-
global.document = dom.window.document
|
|
7
|
-
const parent = document.createElement("div")
|
|
8
|
-
const node = document.createElement("div")
|
|
9
|
-
parent.appendChild(node)
|
|
10
|
-
return new Promise(resolve => {
|
|
11
|
-
const stop = app({ ...defs, node })
|
|
12
|
-
setTimeout(() => {
|
|
13
|
-
stop() //prevents any eventual callbacks from calling back
|
|
14
|
-
resolve(parent.firstChild.outerHTML)
|
|
15
|
-
}, 0)
|
|
16
|
-
})
|
|
17
|
-
}
|