@zoijs/core 1.2.0 → 1.3.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/CHANGELOG.md +13 -0
- package/package.json +1 -1
- package/src/core/boundary.js +34 -0
- package/src/index.d.ts +21 -0
- package/src/index.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to Zoijs are documented here. The format is based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/), and Zoijs follows
|
|
5
5
|
[Semantic Versioning](https://semver.org/) (see `VERSIONING.md`).
|
|
6
6
|
|
|
7
|
+
## [1.3.0] — 2026-06-26
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **`boundary(child, fallback)`.** A render-time error boundary: it renders
|
|
11
|
+
`child`, and if `child` throws **synchronously while building its markup** (a
|
|
12
|
+
setup/render error that would otherwise break the whole `mount`), it disposes the
|
|
13
|
+
partial work — so an `effect` created before the throw can't leak — and renders
|
|
14
|
+
`fallback` (a value, or `(error) => value`) instead. Catches synchronous
|
|
15
|
+
setup/render throws only; errors in reactive *updates* are already contained per
|
|
16
|
+
binding, and *async* errors belong to `@zoijs/resource` / `@zoijs/action`'s
|
|
17
|
+
`error()` state. Logs in dev, silent in production. The public surface is now
|
|
18
|
+
**nine** functions (additive MINOR). See [RFC 0004](docs/rfcs/0004-error-boundary.md).
|
|
19
|
+
|
|
7
20
|
## [1.2.0] — 2026-06-26
|
|
8
21
|
|
|
9
22
|
### Added
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// boundary.js — render-time error containment (RFC 0004).
|
|
2
|
+
//
|
|
3
|
+
// boundary(child, fallback) renders `child`; if it throws SYNCHRONOUSLY while
|
|
4
|
+
// building its markup (a setup/render throw that would otherwise break the whole
|
|
5
|
+
// mount), the partial work is torn down and `fallback(error)` is rendered instead.
|
|
6
|
+
//
|
|
7
|
+
// Errors in reactive UPDATES are already contained per-binding by the core; async
|
|
8
|
+
// errors belong to @zoijs/resource / @zoijs/action. This catches the one
|
|
9
|
+
// remaining case — the synchronous setup/render throw.
|
|
10
|
+
|
|
11
|
+
import { createOwner, runWithOwner, disposeOwner } from "../reactivity/owner.js";
|
|
12
|
+
import { isDev } from "../reactivity/env.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @template C, F
|
|
16
|
+
* @param {(() => C) | C} child a component (or value) to render
|
|
17
|
+
* @param {((error: unknown) => F) | F} fallback a value, or (error) => value, shown if child throws
|
|
18
|
+
* @returns {C | F} the child's result, or the fallback's, for a template slot
|
|
19
|
+
*/
|
|
20
|
+
export function boundary(child, fallback) {
|
|
21
|
+
// Run setup in a child scope so anything it creates before a throw (notably an
|
|
22
|
+
// effect, which runs immediately) can be disposed — no zombies. On success the
|
|
23
|
+
// scope nests under the surrounding owner and is disposed with it.
|
|
24
|
+
const owner = createOwner();
|
|
25
|
+
try {
|
|
26
|
+
return runWithOwner(owner, () => (typeof child === "function" ? child() : child));
|
|
27
|
+
} catch (err) {
|
|
28
|
+
disposeOwner(owner);
|
|
29
|
+
if (isDev()) {
|
|
30
|
+
console.error("Zoijs: boundary caught an error during render; showing fallback.", err);
|
|
31
|
+
}
|
|
32
|
+
return typeof fallback === "function" ? fallback(err) : fallback;
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -144,6 +144,27 @@ export function each<T>(
|
|
|
144
144
|
renderFn: (item: T) => TemplateResult
|
|
145
145
|
): EachResult;
|
|
146
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Render `child`; if it **throws synchronously while building its markup** (a
|
|
149
|
+
* setup/render error that would otherwise break the whole `mount`), tear down the
|
|
150
|
+
* partial work and render `fallback` instead. Place the call in a template slot.
|
|
151
|
+
*
|
|
152
|
+
* Catches synchronous setup/render throws only. Errors in reactive *updates* are
|
|
153
|
+
* already contained per binding by the core; *async* errors belong to
|
|
154
|
+
* `@zoijs/resource` / `@zoijs/action`'s `error()` state. It renders once (no reset
|
|
155
|
+
* — re-mount the subtree to retry), logs in dev, and is silent in production.
|
|
156
|
+
*
|
|
157
|
+
* ```ts
|
|
158
|
+
* html`<section>
|
|
159
|
+
* ${boundary(() => RiskyWidget(), (err) => html`<p>Couldn't load this.</p>`)}
|
|
160
|
+
* </section>`
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
export function boundary<C, F>(
|
|
164
|
+
child: (() => C) | C,
|
|
165
|
+
fallback: ((error: unknown) => F) | F
|
|
166
|
+
): C | F;
|
|
167
|
+
|
|
147
168
|
/** Toggle development warnings (default: `dev` is `true`). */
|
|
148
169
|
export function configure(options: { dev?: boolean }): void;
|
|
149
170
|
|
package/src/index.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
export { html } from "./core/html.js";
|
|
9
9
|
export { mount } from "./core/mount.js";
|
|
10
10
|
export { each } from "./core/each.js";
|
|
11
|
+
export { boundary } from "./core/boundary.js";
|
|
11
12
|
export { createState } from "./reactivity/state.js";
|
|
12
13
|
export { computed } from "./reactivity/computed.js";
|
|
13
14
|
export { effect } from "./reactivity/effect.js";
|