@dom-expressions/babel-plugin-jsx 0.50.0-next.15
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/CHANGELOG.md +254 -0
- package/LICENSE +21 -0
- package/README.md +301 -0
- package/index.js +13447 -0
- package/package.json +40 -0
- package/tsconfig.json +18 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# babel-plugin-jsx-dom-expressions
|
|
2
|
+
|
|
3
|
+
## 0.50.0-next.15
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- df03fb8: Move all packages under the `@dom-expressions` npm scope with new names:
|
|
8
|
+
- `dom-expressions` → `@dom-expressions/runtime`
|
|
9
|
+
- `babel-plugin-jsx-dom-expressions` → `@dom-expressions/babel-plugin-jsx`
|
|
10
|
+
- `jsx-dom-expressions-compiler` → `@dom-expressions/jsx-compiler`
|
|
11
|
+
- `hyper-dom-expressions` → `@dom-expressions/hyperscript`
|
|
12
|
+
- `tagged-jsx-dom-expressions` → `@dom-expressions/tagged-jsx`
|
|
13
|
+
|
|
14
|
+
The old unscoped names stop receiving `next` prereleases and remain in use
|
|
15
|
+
only by the Solid 1.x maintenance line published from `main`.
|
|
16
|
+
|
|
17
|
+
`lit-dom-expressions` is dropped from the prerelease line; it has been
|
|
18
|
+
superseded by `@dom-expressions/tagged-jsx`.
|
|
19
|
+
|
|
20
|
+
`@dom-expressions/jsx-compiler` now distributes prebuilt native binaries
|
|
21
|
+
through per-platform packages (`@dom-expressions/jsx-compiler-darwin-x64`,
|
|
22
|
+
`-darwin-arm64`, `-linux-x64-gnu`, `-linux-arm64-gnu`, `-win32-x64-msvc`)
|
|
23
|
+
resolved automatically via `optionalDependencies`, instead of shipping a
|
|
24
|
+
binary inside the main package.
|
|
25
|
+
|
|
26
|
+
## 0.50.0-next.14
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- 9a64f1f: Preserve SSR child evaluation order for deferred hydratable insert slots.
|
|
31
|
+
|
|
32
|
+
## 0.50.0-next.13
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- f1bcd5f: Stop giving special compiler handling to `style:foo` and `class:foo` JSX namespace syntax, and rename the static compiler marker from `@once` to `@static`. `style:foo` and `class:foo` now fall through to literal HTML attributes (e.g. `<div style:border="1px solid black">` emits `style:border` verbatim).
|
|
37
|
+
|
|
38
|
+
Internal optimizations still split `style={{...}}` into `setStyleProperty` calls and `class={{...}}` into `classList.toggle` calls.
|
|
39
|
+
|
|
40
|
+
- f17f7a1: Rename the generated event listener helper from `addEventListener` to `addEvent` so compiled browser bundles no longer introduce a binding that can shadow the native `window.addEventListener` method.
|
|
41
|
+
|
|
42
|
+
## 0.50.0-next.12
|
|
43
|
+
|
|
44
|
+
### Patch Changes
|
|
45
|
+
|
|
46
|
+
- Port relevant maintenance fixes from the stable branch. Add `omitAttributeSpacing` for strict template attribute spacing, and align `server.js`/`server.d.ts` with the current `client.d.ts` export surface so isomorphic imports continue to resolve on the server.
|
|
47
|
+
|
|
48
|
+
## 0.50.0-next.11
|
|
49
|
+
|
|
50
|
+
### Patch Changes
|
|
51
|
+
|
|
52
|
+
- d5cd499: Remove `on:` namespace event support from compiler, runtime, JSX types, and renderer packages.
|
|
53
|
+
|
|
54
|
+
## 0.50.0-next.10
|
|
55
|
+
|
|
56
|
+
### Patch Changes
|
|
57
|
+
|
|
58
|
+
- ba2c493: Update the JSX compiler source to TypeScript and refresh its generated output expectations for the current Babel and Rollup toolchain.
|
|
59
|
+
|
|
60
|
+
## 0.50.0-next.9
|
|
61
|
+
|
|
62
|
+
## 0.50.0-next.8
|
|
63
|
+
|
|
64
|
+
## 0.50.0-next.7
|
|
65
|
+
|
|
66
|
+
### Patch Changes
|
|
67
|
+
|
|
68
|
+
- 0bd165e: Preserve shared class tokens when diffing object keys that contain multiple class names.
|
|
69
|
+
Ensure class-method JSX captures `this` before lifted DOM setup statements run.
|
|
70
|
+
- e7831bd: Optimize class arrays with leading static class strings and a fixed-shape class object so the static classes are emitted in the template and dynamic object entries compile to class toggles.
|
|
71
|
+
- 10f3250: SSR: group contiguous attribute and `textContent` closures into a single
|
|
72
|
+
`_$ssrGroup(() => […], N)` call per element so the runtime can resolve
|
|
73
|
+
all `N` hole positions with one closure invocation instead of `N`. The
|
|
74
|
+
compiler walks each top-level element's `templateValues`, identifies
|
|
75
|
+
runs of `≥2` groupable entries (inserts/children break a run, preserving
|
|
76
|
+
child isolation), and replaces them with one grouped declarator repeated
|
|
77
|
+
`N` times in the `ssr(...)` argument list. `_$ssrGroup` tags the
|
|
78
|
+
function with `fn.$g = N` so `ssr()` can dispatch through a fast path
|
|
79
|
+
that's gated at the end of the typeof chain — non-function holes pay
|
|
80
|
+
nothing for the new branch.
|
|
81
|
+
|
|
82
|
+
For the async escalation path (group fn throws `NotReadyError`), every
|
|
83
|
+
retry slot for the group shares a module-scoped cache keyed on `fn`:
|
|
84
|
+
slot 0 evaluates and caches `arr` (success) or `err` (still-pending),
|
|
85
|
+
slots `1..N-1` short-circuit on the cached outcome, and the cache
|
|
86
|
+
invalidates when slot 0 re-fires next pass. Net retry cost: 1 evaluation
|
|
87
|
+
per group per pass on either outcome — `N²` → `N` on success, `N²` → `1`
|
|
88
|
+
on failure — with no per-state bookkeeping.
|
|
89
|
+
|
|
90
|
+
Bench: `+15%` on `search-results` (heavy attribute usage), neutral on
|
|
91
|
+
`color-picker` (no qualifying groups). Hydration ids are unaffected:
|
|
92
|
+
attribute/textContent expressions never allocate ids, and inserts (which
|
|
93
|
+
do) stay outside groups by construction.
|
|
94
|
+
|
|
95
|
+
- 3574228: SSR rendering performance pass.
|
|
96
|
+
|
|
97
|
+
**Runtime (`dom-expressions`):**
|
|
98
|
+
- Inline hole resolution in `ssr()`. Switch from a `(t, ...nodes)` rest
|
|
99
|
+
parameter to an `arguments` walk, eliminating the per-call holes-array
|
|
100
|
+
allocation. Inline `string`/`number`/`null`/`boolean` fast paths skip
|
|
101
|
+
`tryResolveString` for the typical "all-static-after-eval" hole shape; only
|
|
102
|
+
the heavy path (async escalation) materializes the `{ t, h, p }` result.
|
|
103
|
+
- Single forward-pass `escape()`. The previous implementation walked the
|
|
104
|
+
string twice in the hot path (`indexOf(delim)` + `indexOf("&")` upfront
|
|
105
|
+
then early-exit on the no-hit case). Replaced with a `charCodeAt` loop
|
|
106
|
+
that bails after one pass for clean strings (the common case), and
|
|
107
|
+
resumes the slow path from the first hit so the clean prefix isn't
|
|
108
|
+
re-scanned.
|
|
109
|
+
- Remove the `ssrRunInScope` public export. The function had been a true
|
|
110
|
+
pass-through identity (`fn => fn`) since owner-capture moved into
|
|
111
|
+
`tryResolveString`'s `NotReadyError` handler, and the compiler stopped
|
|
112
|
+
emitting it. With no internal callers and no behavior, the export was
|
|
113
|
+
dead surface area. User code that called it can drop the wrap (it was a
|
|
114
|
+
no-op) or replicate the original deferred-callback owner-capture intent
|
|
115
|
+
in two lines with `getOwner()` + `runWithOwner()`.
|
|
116
|
+
|
|
117
|
+
**Compiler (`babel-plugin-jsx-dom-expressions`):**
|
|
118
|
+
- IIFE elision in statement-position JSX. When `<jsx/>` is the argument of
|
|
119
|
+
a `return` or the initializer of a `const` (the overwhelmingly common
|
|
120
|
+
shapes), the surrounding IIFE is removed and the body lifts to flat
|
|
121
|
+
statements before the parent. Saves one closure allocation + one
|
|
122
|
+
function-call frame per render. Applies to `dom`, `ssr`, and `universal`
|
|
123
|
+
emissions; expression-position JSX (ternary branches, array elements,
|
|
124
|
+
function args) keeps the IIFE since lifting would change observable
|
|
125
|
+
evaluation semantics.
|
|
126
|
+
- SSR templates emit hoisted `var` declarations for dynamic-expression temp
|
|
127
|
+
vars instead of wrapping the whole thing in an IIFE. In statement
|
|
128
|
+
position the declarations precede the `ssr(...)` call; in expression
|
|
129
|
+
position they hoist to the enclosing function scope and the
|
|
130
|
+
assignment + call become a comma sequence expression.
|
|
131
|
+
- Drop `ssrRunInScope` emission around dynamic SSR expressions. The
|
|
132
|
+
temp-var hoist stays — it's a V8 IC-stability tactic (keeps the `ssr()`
|
|
133
|
+
call site specialized on `Identifier` argument shapes), not an
|
|
134
|
+
evaluation-order requirement. Ordering is preserved by JS left-to-right
|
|
135
|
+
semantics.
|
|
136
|
+
- Drop `createComponent` wrap on SSR component invocations. The SSR
|
|
137
|
+
runtime's `createComponent` is `Comp(props || {})`; the compiler always
|
|
138
|
+
emits a real `props` object, so the `|| {}` fallback never fires. Inline
|
|
139
|
+
to a direct `Comp(props)` call. DOM / dev modes keep the wrapper since
|
|
140
|
+
it does real work (`untrack`, dev metadata).
|
|
141
|
+
|
|
142
|
+
Net effect on representative SSR shapes (color-picker, search-results) is
|
|
143
|
+
fewer allocations per render and a flatter call graph through the hot path.
|
|
144
|
+
|
|
145
|
+
- 6ae1a40: Replace the `wrapDynamics` previous-value default-object initializer with optional chaining for both DOM and universal generators. The combined-effect arrow now takes `(_v$, _p$) => …` and reads `_p$?.<n>` instead of receiving an `_p$ = { 0: undefined, 1: undefined, … }` defaulted object literal. Removes a per-render-effect setup allocation, shrinks compiled output, and matches the shape used elsewhere in the runtime. The DOM generator special-cases `textContent` (`!_p$ || a !== _p$.a`) to keep the first-run write semantics.
|
|
146
|
+
|
|
147
|
+
## 0.50.0-next.6
|
|
148
|
+
|
|
149
|
+
## 0.50.0-next.5
|
|
150
|
+
|
|
151
|
+
## 0.50.0-next.4
|
|
152
|
+
|
|
153
|
+
## 0.50.0-next.3
|
|
154
|
+
|
|
155
|
+
### Patch Changes
|
|
156
|
+
|
|
157
|
+
- 4dae801: Normalize the `repository` field in every package to the standard npm
|
|
158
|
+
convention: a `git+https://github.com/ryansolid/dom-expressions.git` URL
|
|
159
|
+
with a `directory` pointing at the package within the monorepo. Restores
|
|
160
|
+
"View source" / "Open in repo" links on the npm registry and unblocks
|
|
161
|
+
tooling that resolves source from package metadata.
|
|
162
|
+
- 1cc342c: Unify the compiler's void-element list with the runtime's `VoidElements` set in `dom-expressions/src/constants`. The compiler previously kept its own array (`src/VoidElements.ts`) that still contained the long-deprecated `keygen` and `menuitem` tags. Both have been removed from the HTML standard and are no longer parsed as void by modern browsers, so the compiler now emits closing tags for them — which is the correct behaviour in current browsers and was a latent bug otherwise. All other void elements are unaffected.
|
|
163
|
+
|
|
164
|
+
## 0.50.0-next.2
|
|
165
|
+
|
|
166
|
+
### Patch Changes
|
|
167
|
+
|
|
168
|
+
- 4d14c82: Fix single-dynamic attribute accessors being silently invoked with the
|
|
169
|
+
previous value. Given `<div style={source()} />`, the compiler previously
|
|
170
|
+
emitted `effect(source, (v, p) => style(el, v, p))`, which causes the
|
|
171
|
+
reactive core to call `source(p)` — leaking `prev` into a user-authored
|
|
172
|
+
accessor that the source expression wrote as a zero-arg call. Polymorphic
|
|
173
|
+
accessors (e.g. atom-style signals) would observe an unexpected argument
|
|
174
|
+
and misbehave.
|
|
175
|
+
|
|
176
|
+
The compute position now emits `() => source()` so the user's call shape
|
|
177
|
+
is preserved. The prior optimization of unwrapping an IIFE
|
|
178
|
+
(`(() => x)()` → `() => x`) is retained since IIFEs are zero-arg and
|
|
179
|
+
cannot leak `prev`.
|
|
180
|
+
|
|
181
|
+
Fixes #510.
|
|
182
|
+
|
|
183
|
+
- 39c207c: Fix a SyntaxError when an element has 222+ merged dynamic attributes
|
|
184
|
+
(solidjs/solid#2682). The internal identifier generator produced `in` at
|
|
185
|
+
index 221, and since these identifiers are emitted as object shorthand
|
|
186
|
+
destructuring bindings, the resulting `({ …, in }) => …` could not be parsed.
|
|
187
|
+
`getNumberedId` now shifts past any natural index that would encode to a JS
|
|
188
|
+
reserved word, keeping the mapping injective and the output at 2 characters
|
|
189
|
+
for all practical dynamic counts.
|
|
190
|
+
- 03da8a5: Fix SSR escaping gaps reachable from JSX, and tighten the compiler so
|
|
191
|
+
redundant runtime `escape` calls drop out of the output.
|
|
192
|
+
|
|
193
|
+
Security fixes:
|
|
194
|
+
- `ssrStyle` and `ssrClassName` now attribute-escape object keys, not
|
|
195
|
+
just values. Previously a user-controlled key in `<div style={{…}} />`
|
|
196
|
+
or `<div class={{…}} />` could break out of the surrounding attribute.
|
|
197
|
+
- Dynamic fragment-child expressions (`<>{state.text}</>`) now compile
|
|
198
|
+
to `_$memo(() => _$escape(expr))`. Element-child expressions already
|
|
199
|
+
escaped via `escapeExpression`; fragment children reached SSR through
|
|
200
|
+
a separate path and were concatenated raw.
|
|
201
|
+
- Computed-key object styles (`style={{ [k]: v }}`) escape the key at
|
|
202
|
+
compile time.
|
|
203
|
+
|
|
204
|
+
Compiler alignment:
|
|
205
|
+
- SSR now matches DOM in rejecting fragments placed directly inside an
|
|
206
|
+
element: `<div><>…</></div>` is a compile error in both renderers.
|
|
207
|
+
Fragments reached via conditionals (`<div>{cond && <>…</>}</div>`)
|
|
208
|
+
remain legal.
|
|
209
|
+
|
|
210
|
+
Compiler optimizations:
|
|
211
|
+
- `escapeExpression` drops the outer `_$escape` wrap on a `JSXFragment`
|
|
212
|
+
when its single significant child is either a dynamic expression
|
|
213
|
+
(compiles to a memoized accessor function, `escape(fn)` is a no-op)
|
|
214
|
+
or a native element (compiles to an `_$ssr(…)` SSR node object,
|
|
215
|
+
`escape(object)` is a no-op). This turns
|
|
216
|
+
`cond && _$escape(_$memo(() => _$escape(state.text)))` into
|
|
217
|
+
`cond && _$memo(() => _$escape(state.text))`, and
|
|
218
|
+
`cond && _$escape(_$ssr(_tmpl$N))` into `cond && _$ssr(_tmpl$N)`.
|
|
219
|
+
|
|
220
|
+
SSR fixtures for `components`, `conditionalExpressions`, `fragments`,
|
|
221
|
+
and `attributeExpressions` regenerate. Each security fix has a JSX
|
|
222
|
+
round-trip test in `packages/dom-expressions/test/ssr/jsx.spec.jsx`
|
|
223
|
+
that feeds hostile input through `renderToString`.
|
|
224
|
+
|
|
225
|
+
- 305d9ce: - SSR: Duplicate attributes in JSX without spreads are now deduplicated —
|
|
226
|
+
`<div class="a" class="b" />` correctly renders as `<div class="b" />`
|
|
227
|
+
(last-wins), matching client behavior. Previously the compiler kept both
|
|
228
|
+
attributes in the output.
|
|
229
|
+
- Client: `setAttributeNS` / `removeAttributeNS` now use matching names when
|
|
230
|
+
clearing namespaced attributes (e.g. `xlink:href`). Previously removal could
|
|
231
|
+
leave the attribute in place because it used the local name while the set
|
|
232
|
+
used the qualified name.
|
|
233
|
+
- Expanded test coverage across all four packages; no other behavior changes.
|
|
234
|
+
|
|
235
|
+
## 0.50.0-next.1
|
|
236
|
+
|
|
237
|
+
### Patch Changes
|
|
238
|
+
|
|
239
|
+
- ee365e0: - `insert()` accepts an optional 5th `options` argument that is forwarded to the
|
|
240
|
+
internal `effect()` call, letting callers (e.g. Solid's `render()`) opt into
|
|
241
|
+
transition-aware initial mounts without otherwise changing `insert`'s
|
|
242
|
+
behavior.
|
|
243
|
+
- SSR: `$dflj(ids)` now materializes every id in the list in a single call
|
|
244
|
+
instead of stopping after the first successful `$dfl`. Callers pass only the
|
|
245
|
+
keys they intend to materialize, which simplifies the primitive and composes
|
|
246
|
+
cleanly for bulk-uncollapse cases (e.g. a group activation revealing several
|
|
247
|
+
held fallbacks at once).
|
|
248
|
+
- SSR: Fix cascading async root holes in the streaming shell. When an inner
|
|
249
|
+
Loading boundary resolved its first chunk while the outer shell was still
|
|
250
|
+
pending, `flushEnd` could call `serializer.flush()` before `doShell()` had
|
|
251
|
+
written the root `_assets` module map, causing seroval to silently drop the
|
|
252
|
+
writes and client hydration to fail with "module was not preloaded". Root
|
|
253
|
+
asset serialization is now memoized and gated on both paths.
|
|
254
|
+
- Type formatting cleanup in `jsx-properties.d.ts`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018-2019 Ryan Carniato
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# Babel Plugin JSX DOM Expressions
|
|
2
|
+
|
|
3
|
+
[](https://github.com/ryansolid/dom-expressions/actions/workflows/main-ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@dom-expressions/babel-plugin-jsx)
|
|
5
|
+

|
|
6
|
+
[](https://gitter.im/dom-expressions/community)
|
|
7
|
+
|
|
8
|
+
This package is a JSX compiler built for [DOM Expressions](https://github.com/ryansolid/dom-expressions) to provide a general JSX to DOM transformation for reactive libraries that do fine grained change detection. This package aims to convert JSX statements to native DOM statements and wrap JSX expressions with functions that can be implemented with the library of your choice. Sort of like a JSX to Hyperscript for fine change detection.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
This plugin treats all lowercase tags as html elements and mixed cased tags as Custom Functions. This enables breaking up your view into components. This library supports Web Component Custom Elements spec. Support for common camelcase event handlers like React, dom safe attributes like class and for, a simple ref property, and parsing of objects for style, and class properties.
|
|
13
|
+
|
|
14
|
+
In general JSX Attribute Expressions are treated as attributes by default, with exception custom elements that will to properties and special fields like `class` and `style`. Plain string attributes will be treated as attributes.
|
|
15
|
+
|
|
16
|
+
This library uses a heuristic to decide whether JSX expressions need dynamic wrapping based on whether they contain function calls or property access. Simple literals and variable expressions won't be wrapped.
|
|
17
|
+
|
|
18
|
+
## Example
|
|
19
|
+
|
|
20
|
+
```jsx
|
|
21
|
+
const view = ({ item }) => {
|
|
22
|
+
const itemId = item.id;
|
|
23
|
+
return (
|
|
24
|
+
<tr class={itemId === selected() ? "danger" : ""}>
|
|
25
|
+
<td class="col-md-1">{itemId}</td>
|
|
26
|
+
<td class="col-md-4">
|
|
27
|
+
<a onClick={e => select(item, e)}>{item.label}</a>
|
|
28
|
+
</td>
|
|
29
|
+
<td class="col-md-1">
|
|
30
|
+
<a onClick={e => del(item, e)}>
|
|
31
|
+
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
|
32
|
+
</a>
|
|
33
|
+
</td>
|
|
34
|
+
<td class="col-md-6"></td>
|
|
35
|
+
</tr>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Compiles to:
|
|
41
|
+
|
|
42
|
+
```jsx
|
|
43
|
+
import { template as _$template } from "dom";
|
|
44
|
+
import { delegateEvents as _$delegateEvents } from "dom";
|
|
45
|
+
import { className as _$className } from "dom";
|
|
46
|
+
import { effect as _$effect } from "dom";
|
|
47
|
+
import { insert as _$insert } from "dom";
|
|
48
|
+
|
|
49
|
+
const _tmpl$ = /*#__PURE__*/ _$template(
|
|
50
|
+
`<tr><td class="col-md-1"></td><td class="col-md-4"><a></a></td><td class="col-md-1"><a><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></a></td><td class="col-md-6"></td></tr>`,
|
|
51
|
+
16
|
|
52
|
+
);
|
|
53
|
+
const view = ({ item }) => {
|
|
54
|
+
const itemId = item.id;
|
|
55
|
+
return (() => {
|
|
56
|
+
const _el$ = _tmpl$.cloneNode(true),
|
|
57
|
+
_el$2 = _el$.firstChild,
|
|
58
|
+
_el$3 = _el$2.nextSibling,
|
|
59
|
+
_el$4 = _el$3.firstChild,
|
|
60
|
+
_el$5 = _el$3.nextSibling,
|
|
61
|
+
_el$6 = _el$5.firstChild;
|
|
62
|
+
_$insert(_el$2, itemId);
|
|
63
|
+
_el$4.$$click = e => select(item, e);
|
|
64
|
+
_$insert(_el$4, () => item.label);
|
|
65
|
+
_el$6.$$click = e => del(item, e);
|
|
66
|
+
_$effect(
|
|
67
|
+
() => selected(),
|
|
68
|
+
_v$ => _$className(_el$, itemId === _v$ ? "danger" : "")
|
|
69
|
+
);
|
|
70
|
+
return _el$;
|
|
71
|
+
})();
|
|
72
|
+
};
|
|
73
|
+
_$delegateEvents(["click"]);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The use of cloneNode improves repeat insert performance and precompilation reduces the number of references to the minimal traversal path. This is a basic example which doesn't leverage event delegation or any of the more advanced features described below.
|
|
77
|
+
|
|
78
|
+
## Example Implementations
|
|
79
|
+
|
|
80
|
+
- [Solid](https://github.com/ryansolid/solid): A declarative JavaScript library for building user interfaces.
|
|
81
|
+
- [ko-jsx](https://github.com/ryansolid/ko-jsx): Knockout JS with JSX rendering.
|
|
82
|
+
- [mobx-jsx](https://github.com/ryansolid/mobx-jsx): Ever wondered how much more performant MobX is without React? A lot.
|
|
83
|
+
|
|
84
|
+
## Plugin Options
|
|
85
|
+
|
|
86
|
+
### moduleName
|
|
87
|
+
|
|
88
|
+
- Type: `string`
|
|
89
|
+
- Required: Yes
|
|
90
|
+
|
|
91
|
+
The name of the runtime module to import the methods from.
|
|
92
|
+
|
|
93
|
+
### generate
|
|
94
|
+
|
|
95
|
+
- Type: `'dom' | 'ssr'`
|
|
96
|
+
- Default: `'dom'`
|
|
97
|
+
|
|
98
|
+
The output mode of the compiler. Can be "dom"(default), "ssr". "dom" is standard output. "ssr" is for server side rendering of strings.
|
|
99
|
+
|
|
100
|
+
### hydratable
|
|
101
|
+
|
|
102
|
+
- Type: `boolean`
|
|
103
|
+
- Default: `false`
|
|
104
|
+
|
|
105
|
+
Indicate whether the output should contain hydratable markers.
|
|
106
|
+
|
|
107
|
+
### delegateEvents
|
|
108
|
+
|
|
109
|
+
- Type: `boolean`
|
|
110
|
+
- Default: `true`
|
|
111
|
+
|
|
112
|
+
Boolean to indicate whether to enable automatic event delegation on camelCase.
|
|
113
|
+
|
|
114
|
+
### wrapConditionals
|
|
115
|
+
|
|
116
|
+
- Type: `boolean`
|
|
117
|
+
- Default: `true`
|
|
118
|
+
|
|
119
|
+
Boolean indicates whether smart conditional detection should be used. This optimizes simple boolean expressions and ternaries in JSX.
|
|
120
|
+
|
|
121
|
+
### contextToCustomElements
|
|
122
|
+
|
|
123
|
+
- Type: `boolean`
|
|
124
|
+
- Default: `false`
|
|
125
|
+
|
|
126
|
+
Boolean indicates whether to set current render context on Custom Elements and slots. Useful for seemless Context API with Web Components.
|
|
127
|
+
|
|
128
|
+
### builtIns
|
|
129
|
+
|
|
130
|
+
- Type: `boolean`
|
|
131
|
+
- Default: `string[]`
|
|
132
|
+
|
|
133
|
+
Array of Component exports from module, that aren't included by default with the library. This plugin will automatically import them if it comes across them in the JSX.
|
|
134
|
+
|
|
135
|
+
### effectWrapper
|
|
136
|
+
|
|
137
|
+
- Type: `string`
|
|
138
|
+
- Default: `effect`
|
|
139
|
+
|
|
140
|
+
This plugin leverages a heuristic for reactive wrapping and lazy evaluation of JSX expressions. This option indicates the reactive wrapper function name (`effect`), defaults to `effect`.
|
|
141
|
+
|
|
142
|
+
### staticMarker
|
|
143
|
+
|
|
144
|
+
- Type: `string`
|
|
145
|
+
- Default: `@static`
|
|
146
|
+
|
|
147
|
+
Advanced compiler assertion marker. When an expression starts with this comment, the compiler treats it as static and does not wrap it in an `effect` call.
|
|
148
|
+
|
|
149
|
+
This is not a reactivity primitive and should not be used to read reactive values once. Only use it when you can prove the expression is non-reactive for the lifetime of the rendered element, and the compiler heuristic cannot infer that on its own.
|
|
150
|
+
|
|
151
|
+
### memoWrapper
|
|
152
|
+
|
|
153
|
+
- Type: `string`
|
|
154
|
+
- Default: `memo`
|
|
155
|
+
|
|
156
|
+
Memos let you efficiently use a derived value in many reactive computations. This option indicates the memo function name, defaults to `memo`.
|
|
157
|
+
|
|
158
|
+
### validate
|
|
159
|
+
|
|
160
|
+
- Type: `boolean`
|
|
161
|
+
- Default: `true`
|
|
162
|
+
|
|
163
|
+
Checks for properly formed HTML by checking for elements that would not be allowed in certain parent elements. This validation isn't complete but includes places where browser would "correct" it and break the DOM walks.
|
|
164
|
+
|
|
165
|
+
### omitNestedClosingTags
|
|
166
|
+
|
|
167
|
+
- Type: `boolean`
|
|
168
|
+
- Default: `false`
|
|
169
|
+
|
|
170
|
+
Removes unnecessary closing tags from the template output. This may not work in all browser-like environments the same. The solution has been tested again Chrome/Edge/Firefox/Safari.
|
|
171
|
+
|
|
172
|
+
### omitLastClosingTag
|
|
173
|
+
|
|
174
|
+
- Type: `boolean`
|
|
175
|
+
- Default: `true`
|
|
176
|
+
|
|
177
|
+
Removes tags from the template output if they have no closing parents and are the last element. This may not work in all browser-like environments the same. The solution has been tested again Chrome/Edge/Firefox/Safari.
|
|
178
|
+
|
|
179
|
+
### omitQuotes
|
|
180
|
+
|
|
181
|
+
- Type: `boolean`
|
|
182
|
+
- Default: `true`
|
|
183
|
+
|
|
184
|
+
Removes quotes for html attributes when possible from the template output. This may not work in all browser-like environments the same. The solution has been tested again Chrome/Edge/Firefox/Safari.
|
|
185
|
+
|
|
186
|
+
### omitAttributeSpacing
|
|
187
|
+
|
|
188
|
+
- Type: `boolean`
|
|
189
|
+
- Default: `true`
|
|
190
|
+
|
|
191
|
+
When `true`, quoted attributes may omit the space before the next attribute. Set this to `false` to emit strictly spaced attributes for stricter HTML/SVG parsers.
|
|
192
|
+
|
|
193
|
+
### requireImportSource
|
|
194
|
+
|
|
195
|
+
- Type: `string | false`
|
|
196
|
+
- Default: `false`
|
|
197
|
+
|
|
198
|
+
When set to a string value, this option restricts JSX transformation to only files that contain a specific JSX import source pragma comment. The plugin will only transform JSX in files that include a comment with `@jsxImportSource` followed by the specified value. If the comment is missing or specifies a different import source, the transformation is skipped for that file.
|
|
199
|
+
Example usage:
|
|
200
|
+
|
|
201
|
+
```jsx
|
|
202
|
+
// In babel configuration:
|
|
203
|
+
{
|
|
204
|
+
plugins: [
|
|
205
|
+
[
|
|
206
|
+
"jsx-dom-expressions",
|
|
207
|
+
{
|
|
208
|
+
requireImportSource: "r-dom"
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
// In your component file:
|
|
214
|
+
/** @jsxImportSource r-dom */
|
|
215
|
+
const template = <div>Hello</div>;
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### inlineStyles
|
|
219
|
+
|
|
220
|
+
- Type: `boolean`
|
|
221
|
+
- Default: `true`
|
|
222
|
+
|
|
223
|
+
Style attributes in templates are inlined when possible: value is a string, `Record<string, string>`, etc. Inlining styles may not be desired when using strong CSP configurations. Disabling `inlineStyles` will cause all of the style definitions to be set at runtime.
|
|
224
|
+
|
|
225
|
+
## Special Binding
|
|
226
|
+
|
|
227
|
+
### ref
|
|
228
|
+
|
|
229
|
+
This binding will assign the variable you pass to it with the DOM element or if a function will call it with the element.
|
|
230
|
+
|
|
231
|
+
```jsx
|
|
232
|
+
const Child = props => <div ref={props.ref} />;
|
|
233
|
+
|
|
234
|
+
const Parent = () => {
|
|
235
|
+
let ref;
|
|
236
|
+
return <Child ref={ref} />;
|
|
237
|
+
};
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### on(eventName)
|
|
241
|
+
|
|
242
|
+
CamelCase event attributes such as `onClick` are treated as event handlers expecting a function. The compiler will delegate events where possible (events that bubble or can be composed), otherwise it falls back to Level 1 spec `on_____` events.
|
|
243
|
+
|
|
244
|
+
If you wish to make it into a Bound Event, you can bind a value to your delegated event by passing an array handler instead and the second argument will be passed to your event handler as the first argument (the event will be second).
|
|
245
|
+
|
|
246
|
+
```jsx
|
|
247
|
+
function handler(itemId, e) {
|
|
248
|
+
/*...*/
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
<ul>
|
|
252
|
+
{list().map(item => (
|
|
253
|
+
<li onClick={[handler, item.id]} />
|
|
254
|
+
))}
|
|
255
|
+
</ul>;
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
This delegation solution works with Web Components and the Shadow DOM as well if the events are composed. That limits the list to custom events and most UA UI events like onClick, onKeyUp, onKeyDown, onDblClick, onInput, onMouseDown, onMouseUp, etc..
|
|
259
|
+
Important:
|
|
260
|
+
|
|
261
|
+
- To allow for casing to work, custom delegated events should follow the all lowercase convention of native events. Use a ref/directive that calls `addEventListener` when you need native listener options or custom event casing.
|
|
262
|
+
|
|
263
|
+
- Event delegates are owned by render roots and are removed when those roots dispose.
|
|
264
|
+
|
|
265
|
+
### ... (spreads)
|
|
266
|
+
|
|
267
|
+
Spreads let you pass multiple props at once:
|
|
268
|
+
|
|
269
|
+
```jsx
|
|
270
|
+
<div {...props} />
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Keep in mind given the independent nature of binding updates there is no guarantee of order using spreads at this time. It's under consideration.
|
|
274
|
+
|
|
275
|
+
## Components
|
|
276
|
+
|
|
277
|
+
Components are just Capital Cased tags. Instead of wrapping with computation dynamic props will just be getter accessors. \* Remember property access triggers so don't destructure outside of computations unless you intend the content to be static.
|
|
278
|
+
|
|
279
|
+
```jsx
|
|
280
|
+
const MyComp = props => {
|
|
281
|
+
const staticProp = props.other;
|
|
282
|
+
return (
|
|
283
|
+
<>
|
|
284
|
+
<div>{props.param}</div>
|
|
285
|
+
<div>{staticProp}</div>
|
|
286
|
+
</>
|
|
287
|
+
);
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
<MyComp param={dynamic()} other={static} />;
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Components may have children. This is available as props.children. It may be a node, a function, or a string, or an array of the aforementioned. Non-expression children like DOM nodes are set to evaluate lazily (upon access by default).
|
|
294
|
+
|
|
295
|
+
## Fragments
|
|
296
|
+
|
|
297
|
+
This plugin also supports JSX Fragments with `<></>` notation. These will be compiled to arrays. The fragment syntax provides the convenience of being able to use the template syntax to wrap expressions.
|
|
298
|
+
|
|
299
|
+
## Acknowledgements
|
|
300
|
+
|
|
301
|
+
The concept of using JSX to DOM instead of html strings and context based binding usually found in these libraries was inspired greatly by [Surplus](https://github.com/adamhaile/surplus).
|