GeezerVison is showing github.com — Release 1.16.0 — quality & performance pass by JosunLP · Pull Request #203 · bQuery/bQuery
Conversation
Release 1.16.0 — Quality & performance pass
Promotes dev to main for the 1.16.0 minor release. A full audit of the framework's three hot paths — the reactive core, the DOM core, and the view layer — drove measurable speed-ups and surfaced several real correctness bugs, all fixed here. The release also folds in the previously staged follow-up to the 1.15.1 security review, plus a documentation-wide accuracy pass.
No breaking changes. No module status transitions. The only new API is the additive trailing option on watchThrottle.
Performance (benchmarked old vs. new)
| Area |
Change |
Measured effect |
| reactive |
batch() keeps the batch open while flushing; transitive updates coalesce, re-queued observers drain in follow-up passes (bounded at 100) |
diamond dependencies: 1 effect run per batch instead of 1 per branch |
| reactive |
Computed re-validates and notifies subscribers only when the value actually changed (Object.is) |
unchanged computed bool under 20k writes: 20k effect runs → 2 |
| reactive |
allocation cuts on signal writes and dependency tracking |
writes w/o subscribers ~6× faster; repeated reads ~1.6×; computed chains ~1.7× |
| core |
replaceWith(string) sanitizes once per call; empty() → replaceChildren(); children()/siblings()/index()/unwrap()/css(object)/data() shed per-element allocations |
fewer sanitizer runs, HTML parses, and array copies on collection ops |
| view |
per-update work moved to bind time: object-expression parsing, transition resolution, memoized directive parsing, sandbox proxies cached per context; unchanged DOM writes skipped |
less garbage and fewer DOM writes per reactive tick, faster bq-for reconciles |
Correctness fixes
| Area |
Fix |
| core |
undelegate() from a fresh wrapper (the documented usage) was a silent no-op leaking the listener — registry is now module-level, delegate() idempotent per (element, event, selector, handler); delegated dispatcher tolerates non-Element targets |
| core |
wrap(element) over multi-element collections no longer clones previously wrapped elements into later wrappers |
| view |
directives declared before bq-for on the same element no longer bind to the discarded template element |
| view |
bq-once/bq-memo/bq-init evaluate untracked — they no longer subscribe the enclosing bq-for reconciler |
| view |
bq-model no longer resets the caret while typing (skips the write-back when the input already holds the value) |
| view |
children of bq-html/bq-html-safe are no longer directive-bound (effects kept running against replaced markup) |
| reactive |
nested batch() no longer double-executes observers; a throwing computed stays dirty and retries instead of serving a stale cache |
| motion |
onReducedMotionChange re-binds to the current window.matchMedia on subscribe and flushes changes that happened without a change event (also fixes two order-dependent motion tests) |
| store |
deepClone special-cases only the dangerous __proto__ key; properties merely named constructor/prototype clone normally again |
| view/compiler |
rejects legacy leading-zero decimal literals instead of emitting strict-mode SyntaxErrors |
Security (1.15.1 follow-up)
with-scope evaluator hardening closes a residual member-access escape (items.constructor.constructor('…')()) via the shared hasDangerousMemberAccess() guard, applied to both the runtime evaluator and the AOT compiler (#168, #202).
Additive API (backwards-compatible)
watchThrottle(source, cb, interval, { trailing: true }) — delivers the last value of a burst once the interval elapses; default stays leading-edge-only (WatchThrottleOptions, @bquery/bquery/reactive).
Behavioral notes (no opt-out needed)
- Effects depending on a computed re-run without a value change now run less often — matching the documented contract. Read the underlying signal directly if you relied on the extra runs.
delegate() no longer stacks duplicate listeners for the same handler tuple.
Documentation accuracy pass
- ~40 factual errors fixed across the view/reactive/core guides and concepts pages (nonexistent APIs like
.set()/cloneDeep/bq-attr removed, bq-memo/bq-error/bq-model described as implemented, broken examples repaired).
- 20 broken in-site anchors (cookbook/workflows → reactive guide) and the contradicting 1.15.0 release date (now consistently 2026-06-30) fixed.
- AI guidance files carry full 1.15.1 + 1.16.0 sections;
check:doc-exports now reports 100 % export coverage for all 21 modules.
Release chores
package.json: 1.15.1 → 1.16.0 (the staged 1.15.2 patch was folded into this minor)
CHANGELOG.md: new [1.16.0] section (Added/Changed/Fixed/Security) and TOC entry
- Docs: new
release-notes/1.16 page, nav + index entries, version-history entries in the affected guides
- Dev dependencies: Storybook 10.5.7, typescript-eslint 8.67.0, ESLint 10.8.1, happy-dom 20.11.2, Prettier 3.9.6, Vite 8.2.1
Validation
bun test: 3056 pass / 0 fail (8 new regression tests)
tsc --noEmit (src + component-test config): clean
bun run build (ESM + UMD + types) and bun run docs:build: succeed
check:stability, check:full-bundle, check:ai-guidance, check:doc-exports (21/21 modules at 100 %): pass
🤖 Generated with Claude Code
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
…est files
- Refactored test cases in `ssr-runtime.test.ts` for better readability by aligning parameters and breaking long lines.
- Updated `ssr-stable.test.ts` to enhance clarity by formatting multi-line function calls.
- Cleaned up `storybook.test.ts` by consolidating assertions into single lines.
- Simplified `testing-extensions.test.ts` by streamlining error expectations.
- Enhanced `utils-array-extras.test.ts` and `utils-function-extras.test.ts` for better visual structure.
- Improved `utils-misc-extras.test.ts` and `utils-object-extras.test.ts` by formatting complex assertions.
- Refined `view-1-14.test.ts` and `view-compiler.test.ts` for consistency in line breaks and indentation.
- Added new tests in `view-process-order.test.ts` to cover directive processing order and subscription hygiene.
- Updated `view-stable.test.ts` and `view-transitions.test.ts` for better readability and consistency in test structure.
- Enhanced `view.test.ts` for clarity in handler invocation tests.
coderabbitai
Bot
commented
Aug 11, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
❤️ Share
Comment @coderabbitai help to get the list of available commands.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
github-actions
Bot
added
core
Changes to the core module
reactive
Changes to the reactive module
component
Changes to the component module
motion
Changes to the motion module
router
Changes to the router module
view
Changes to the view module
docs
Changes to the documentation
tests
Chenges to the tests
build
Changes to the build and meta files
github
Changes to the github meta data files
forms
Changes to the forms module
i18n
Changes to the i18n module
a11y
Changes to the a11y module
dnd
Changes to the dnd module
media
Changes to the media module
plugin
Changes to the plugin module
devtools
Changes to the devtools module
testing
Changes to the testing module
ssr
Changes to the ssr module
storybook
Changes to the storybook module
concurrency
server
labels
Aug 11, 2026
…bscribe
onReducedMotionChange flushed pending value changes before ensuring the
matchMedia subscription existed. When a baseline (lastDispatchedValue) was
left behind by setReducedMotion() without an active subscription — a state
CI's test-file ordering produced — the flush issued a one-off matchMedia
call and ensure() then subscribed again, so a freshly mocked matchMedia saw
two calls instead of one. Establish the subscription first so evaluation
reads the cached media query; add a deterministic regression test for the
baseline-without-subscription state.
Co-Authored-By: Claude Fable 5 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review (workflow-assisted, high effort): 8 findings — 5 confirmed against the code, 3 plausible. Ranked by severity in the inline comments. The two computed.ts issues can permanently freeze subscribers and look like release blockers for 1.16.0.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Correctness:
- computed: markDirty no longer early-returns on an already-dirty computed.
A compute that threw (or a revalidate dropped by a flush-pass overflow)
left dirty=true with no pending revalidate, so every later dependency
change was ignored and subscribers stayed frozen.
- computed: rebase the notified-value baseline when a subscriber joins a
previously empty set, so a change made while nobody was subscribed
followed by a revert is no longer swallowed by the equality check. Adds a
stale-baseline guard for readers that observe an un-notified value.
- view/process: restore the children snapshot in processChildren. The live
nextElementSibling walk silently dropped every remaining sibling once a
directive handler removed the node it was standing on.
- view/text: only skip the write when the element already is exactly that
single text node. Comparing el.textContent alone left server-rendered
markup (<b>Hel</b>lo) in place instead of flattening it.
- view/if,show: resolve transitions inside the effect again so attributes
added or changed after mount take effect (bq-if resolves per flip).
- core/shared: count delegated registrations so one owner's undelegate()
cannot detach a delegation another owner still holds.
Efficiency:
- view/process: bound the parseDirective memo like the expression caches so
generated attribute names cannot grow it without eviction.
Co-Authored-By: Claude Opus 5 <[email protected]>
tsconfig.component-test.json targets a lib without es2022 array methods,
so `.at(-1)` failed the test type-check in CI.
Co-Authored-By: Claude Opus 5 <[email protected]>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Labels
a11y
Changes to the a11y module
build
Changes to the build and meta files
component
Changes to the component module
concurrency
core
Changes to the core module
devtools
Changes to the devtools module
dnd
Changes to the dnd module
docs
Changes to the documentation
forms
Changes to the forms module
github
Changes to the github meta data files
i18n
Changes to the i18n module
media
Changes to the media module
motion
Changes to the motion module
plugin
Changes to the plugin module
reactive
Changes to the reactive module
router
Changes to the router module
server
ssr
Changes to the ssr module
storybook
Changes to the storybook module
testing
Changes to the testing module
tests
Chenges to the tests
view
Changes to the view module
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|