@kudzujs/core 0.8.9 → 0.8.11
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 +5 -1
- package/RELEASES.md +56 -0
- package/framework/build.mjs +12 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,9 +8,13 @@ HTML-first TSX framework with synchronous state semantics and no virtual DOM.
|
|
|
8
8
|
|
|
9
9
|
Kudzu compiles ordinary React-shaped TypeScript and TSX into complete static HTML, CSS, and only the route-specific ESM capabilities actually used. Static pages ship zero JavaScript. React, hydration, a VDOM, and a retained browser component tree are not part of the output.
|
|
10
10
|
|
|
11
|
+
[](https://github.com/kudzujs/kudzu/blob/main/media/kudzu-demo.mp4)
|
|
12
|
+
|
|
13
|
+
*Watch: React-shaped TSX to static HTML and route-specific ESM in 22 seconds.*
|
|
14
|
+
|
|
11
15
|
> Experimental `0.8.x`: the compiler API and supported TSX surface may change.
|
|
12
16
|
|
|
13
|
-
**Latest release: 0.8.
|
|
17
|
+
**Latest release: 0.8.11 - Stale-safe data migration.** Build-known query data moves to async pages, browser-only reads move to route effects, and superseded promise or fetch setters can no longer overwrite newer state. Read the [release notes](./RELEASES.md#0811---stale-safe-data-migration) or open the [release page](https://kudzujs.cloud/releases/0.8.11).
|
|
14
18
|
|
|
15
19
|
- [Documentation](https://kudzujs.cloud/docs)
|
|
16
20
|
- [Installation guide](https://kudzujs.cloud/docs#install)
|
package/RELEASES.md
CHANGED
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
# Kudzu Releases
|
|
2
2
|
|
|
3
|
+
## 0.8.11 - Stale-safe data migration
|
|
4
|
+
|
|
5
|
+
Kudzu 0.8.11 proves source migration paths for TanStack Query-shaped data and React Hook Form-shaped forms while strengthening dependency-effect stale-write isolation.
|
|
6
|
+
|
|
7
|
+
### New in 0.8.11
|
|
8
|
+
|
|
9
|
+
- Build-known query data moves to async pages and emits complete zero-JavaScript HTML.
|
|
10
|
+
- Browser-only query data uses one dependency effect with application-owned loading, error, result, and primitive refetch state.
|
|
11
|
+
- Superseded unowned dependency effects invalidate their invocation before cleanup, so late promise or fetch setters cannot overwrite newer state.
|
|
12
|
+
- A deterministic Chrome race verifies that a fast refetch remains visible after a delayed prior response arrives, followed by HTTP failure and recovery.
|
|
13
|
+
- React Hook Form-shaped signup source migrates to native controls, constraint validation, `FormData`, one async submit handler, accessible server errors, and retained uncontrolled values.
|
|
14
|
+
- Static sibling routes remain JavaScript-free, with no TanStack Query or React Hook Form runtime in deploy output.
|
|
15
|
+
|
|
16
|
+
### Fixed in 0.8.11
|
|
17
|
+
|
|
18
|
+
- Mobile documentation now uses a true 100% layout wrapper with explicit inner gutters instead of a reduced outer width.
|
|
19
|
+
- The complete suite passes 142/142 tests.
|
|
20
|
+
|
|
21
|
+
### Boundary
|
|
22
|
+
|
|
23
|
+
This release does not execute TanStack Query or React Hook Form. Query clients, Providers, caches, retries, deduplication, optimistic cache updates, query-key arrays, Suspense, controllers, watchers, resolvers, and dynamic field registration remain source migration work.
|
|
24
|
+
|
|
25
|
+
### Upgrade
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @kudzujs/core@^0.8.11
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 0.8.10 - Native dialog migration
|
|
32
|
+
|
|
33
|
+
Kudzu 0.8.10 proves a source migration path from a shadcn/Radix-shaped dialog to the native `<dialog>` element without adding package compatibility runtime.
|
|
34
|
+
|
|
35
|
+
### New in 0.8.10
|
|
36
|
+
|
|
37
|
+
- A reduced migration fixture preserves a relative `forwardRef` component, props, children, object refs, and ordinary JSX event handlers.
|
|
38
|
+
- Package-owned Portal and Context behavior becomes native `showModal()`, `close()`, and cancel handling.
|
|
39
|
+
- Complete accessible dialog markup is pre-rendered while route output includes only the `click` and `cancel` events it uses.
|
|
40
|
+
- Chrome coverage verifies modal top-layer behavior, initial focus, confirm and cancel paths, and explicit trigger-focus restoration.
|
|
41
|
+
- Public documentation now includes the migration recipe and its deliberate library boundary.
|
|
42
|
+
|
|
43
|
+
### Fixed in 0.8.10
|
|
44
|
+
|
|
45
|
+
- Mobile documentation code blocks stay within the content grid and scroll horizontally instead of widening the viewport.
|
|
46
|
+
- Browser tests allow slower CI Chrome startup and report process timeouts directly instead of failing later against empty DOM output.
|
|
47
|
+
- The complete suite passes 140/140 tests.
|
|
48
|
+
|
|
49
|
+
### Boundary
|
|
50
|
+
|
|
51
|
+
This release does not execute Radix or arbitrary React UI packages. `Portal`, `asChild`/`Slot`, element cloning, and arbitrary compound-component Context must be removed during source migration. Applications remain responsible for dialog labeling and explicit focus restoration.
|
|
52
|
+
|
|
53
|
+
### Upgrade
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install @kudzujs/core@^0.8.10
|
|
57
|
+
```
|
|
58
|
+
|
|
3
59
|
## 0.8.9 - Context-backed CRUD actions
|
|
4
60
|
|
|
5
61
|
Kudzu 0.8.9 specializes state-backed actions exposed through one conventional Context Provider and relative custom hook.
|
package/framework/build.mjs
CHANGED
|
@@ -581,7 +581,7 @@ addEventListener("pagehide", event => {
|
|
|
581
581
|
if (hasDependencies) return `${imports.join("\n")}
|
|
582
582
|
const effects = ${inlineJson(effects)}
|
|
583
583
|
const modules = new Map([${entries}])
|
|
584
|
-
const records = effects.map((effect, index) => ({ effect, index, values: undefined, cleanup: undefined }))
|
|
584
|
+
const records = effects.map((effect, index) => ({ effect, index, values: undefined, cleanup: undefined, token: undefined }))
|
|
585
585
|
const dependencies = new Map()
|
|
586
586
|
const pending = new Set()
|
|
587
587
|
let scheduled = false
|
|
@@ -649,7 +649,9 @@ ${hasDependencyExpressions ? printDerivedDependencyRead("browserState") : ""}
|
|
|
649
649
|
function invoke(record) {
|
|
650
650
|
try {
|
|
651
651
|
const effect = record.effect
|
|
652
|
-
const
|
|
652
|
+
const token = { active: true }
|
|
653
|
+
record.token = token
|
|
654
|
+
const result = modules.get(effect.module)[effect.handler](createEffectContext(browserState, effect.states, commitDom, effect.scope, () => active && token.active && record.token === token))
|
|
653
655
|
if (effect.cleanup && typeof result === "function") record.cleanup = result
|
|
654
656
|
else if (result && typeof result.then === "function") result.catch(error => console.error(error))
|
|
655
657
|
} catch (error) {
|
|
@@ -657,6 +659,8 @@ function invoke(record) {
|
|
|
657
659
|
}
|
|
658
660
|
}
|
|
659
661
|
async function invokeCleanup(record) {
|
|
662
|
+
if (record.token) record.token.active = false
|
|
663
|
+
record.token = undefined
|
|
660
664
|
const cleanup = record.cleanup
|
|
661
665
|
record.cleanup = undefined
|
|
662
666
|
if (!cleanup) return
|
|
@@ -1352,6 +1356,7 @@ const effect = ${inlineJson(effect)}
|
|
|
1352
1356
|
const dependency = effect.dependencies[0]
|
|
1353
1357
|
let value
|
|
1354
1358
|
let cleanup
|
|
1359
|
+
let token
|
|
1355
1360
|
let active = true
|
|
1356
1361
|
let pending = false
|
|
1357
1362
|
let scheduled = false
|
|
@@ -1402,7 +1407,9 @@ function readDependency() {
|
|
|
1402
1407
|
}
|
|
1403
1408
|
function invoke() {
|
|
1404
1409
|
try {
|
|
1405
|
-
const
|
|
1410
|
+
const current = { active: true }
|
|
1411
|
+
token = current
|
|
1412
|
+
const result = __kEffectModule0[effect.handler](createEffectContext(browserState, effect.states, commitDom, effect.scope, () => active && current.active && token === current))
|
|
1406
1413
|
if (effect.cleanup && typeof result === "function") cleanup = result
|
|
1407
1414
|
else if (result && typeof result.then === "function") result.catch(error => console.error(error))
|
|
1408
1415
|
} catch (error) {
|
|
@@ -1410,6 +1417,8 @@ function invoke() {
|
|
|
1410
1417
|
}
|
|
1411
1418
|
}
|
|
1412
1419
|
async function invokeCleanup() {
|
|
1420
|
+
if (token) token.active = false
|
|
1421
|
+
token = undefined
|
|
1413
1422
|
const current = cleanup
|
|
1414
1423
|
cleanup = undefined
|
|
1415
1424
|
if (!current) return
|