Skip to content

Document the terminated marker contract and pin it with tests - #750

Open
titouanmathis wants to merge 2 commits into
3.xfrom
fix/mutation-scan-remount-and-swap-order
Open

Document the terminated marker contract and pin it with tests#750
titouanmathis wants to merge 2 commits into
3.xfrom
fix/mutation-scan-remount-and-swap-order

Conversation

@titouanmathis

@titouanmathis titouanmathis commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

What

Document and pin an unguarded contract in the mount scan, and correct two claims the first version of this branch got wrong.

Docs + tests only. No behavior change.

The contract

$terminate() stamps the element's __base__ entry with a 'terminated' marker instead of deleting it. That marker is truthy, so getInstanceFromElement() returns it and the document-wide auto-mount scan (mutationCallback in Base/utils.ts) treats the element as already having an instance and skips it — forever, including when the very same node is re-inserted into the DOM.

Before this PR, packages/js-toolkit/Base/utils.ts:194 — the line that decides this — was guarded by no test at all. Mutating it to ignore the 'terminated' marker broke exactly one test out of the whole suite.

Why the marker exists

Commit 9bc6f838 ("Fix terminated feature", Feb. 2022) changed __base__.delete(...) to __base__.set(..., 'terminated'). The one-line change made an already existing filter work: ChildrenManager was already doing .filter((instance) => instance !== 'terminated'), but with the entry deleted, __getChild() fell through and constructed a fresh instance instead. The marker is what keeps terminated elements excluded from $children, $parent and queryComponent() resolution.

The sharp edge

You rarely call $terminate() yourself. The second pass of mutationCallback() terminates any instance whose element is no longer connected. So removing an element from the DOM is enough to permanently disable it for the auto-mount scan — animated modal teardown, virtual-list recycling, view transitions and drag & drop re-parenting all hit this without anyone typing $terminate().

This combination is emergent, not designed: the marker landed in Feb. 2022 and the terminate-on-disconnect pass in Dec. 2024 (issue #552), for unrelated reasons. The docs frame it as a sharp edge with stated workarounds, not as intent.

Changes

  • packages/js-toolkit/Base/Base.ts — rewrote the $terminate() JSDoc: the real (git-supported) rationale, the mount-scan consequence scoped to the automatic scan, both escape hatches, and the disconnect scan named as the actual caller.
  • packages/js-toolkit/Base/utils.ts — comment on the mount-scan site explaining why a truthy marker skips the element and what that does and does not imply.
  • packages/docs/api/instance-methods.md — new ### Removing an element terminates its component section under $terminate(): the auto-terminate behavior, the re-insertion no-op, and three workarounds (re-parent synchronously, insert a new node, instantiate explicitly), plus a tip pointing at $destroy() + $mount().
  • packages/tests/Base/utils.spec.ts — two regression tests in their own describe('The terminated marker and the auto-mount scan') block:
    1. re-inserting a terminated node is never auto-mounted, with a positive control: a brand new element inserted in the same mutation batch does mount, so the assertions on the terminated node are a real "skipped", not a "the observer never fired";
    2. new Ctor(el).$mount() does mount a terminated node — pinning the escape hatch the docs now promise.

Corrections vs. the first version of this branch

Two claims in the initial commit were wrong and are removed:

  1. "it backs lazy/once components such as withMountWhenInView, which must trigger exactly once … and must never re-trigger on the same element" — the opposite is true. withMountWhenInView calls $mount() on enter and $destroy() on leave on every visibility flip, and never calls $terminate() (rg '\$terminate\(' packages/js-toolkit/ hits only the definition and the disconnect scan). Its sole terminated reference is a passive listener that disconnects the observer.
  2. "The only supported way to mount again is to replace the element with a brand new node."Base.ts:441-443 overwrites __base__ unconditionally, so new Ctor(el).$mount() clears the marker and mounts. Verified by running it; now covered by test 2 above.

The initial commit ee95feb1 still carries the first of these in its message — squash on merge so it does not land in history.

Not addressed here

  • The behavior itself is unchanged. Making terminated elements auto-remountable was tried on an earlier branch and rejected as racy.
  • Instantiating explicitly on a terminated element leaves the stale instance in getInstances()$on/$emit use $el as the EventTarget, so the old instance's before-mounted listener fires too. Pre-existing and separate; the test asserts on the instance, not on the count.

Verification

  • Full suite: 137 files, 958 passed, 2 skipped.
  • packages/tests/Base/utils.spec.ts run 5× in isolation: 16 passed each time, no flakiness.
  • npm run lint and npm run build: clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_0114BLVFkrWWJAhmamS6NHB3

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Export Size

Unchanged

@studiometa/js-toolkit

Name Size Diff
AbstractService 528 B -
addClass 226 B -
addStyle 238 B -
ALL 23.92 kB -
animate 3.27 kB -
autoload 2.25 kB -
AUTOLOAD 3.25 kB -
Base 8.92 kB -
BASE 8.97 kB -
boundingRectToCircle 154 B -
cache 194 B -
camelCase 397 B -
clamp 67 B -
clamp01 87 B -
closestComponent 418 B -
collideCircleCircle 99 B -
collideCircleRect 159 B -
collidePointCircle 112 B -
collidePointRect 103 B -
collideRectRect 99 B -
ComponentLoader 2.16 kB -
composeManifests 100 B -
createApp 893 B -
createEaseInOut 116 B -
createEaseOut 71 B -
createElement 592 B -
createLocalStorage 1.19 kB -
createLocalStorageProvider 264 B -
createMemoryStorageProvider 146 B -
createNoopProvider 96 B -
createRange 90 B -
createSessionStorage 1.23 kB -
createSessionStorageProvider 254 B -
createStorage 1.17 kB -
createUrlSearchParamsInHashProvider 413 B -
createUrlSearchParamsInHashStorage 1.22 kB -
createUrlSearchParamsProvider 386 B -
createUrlSearchParamsStorage 1.21 kB -
damp 78 B -
dashCase 372 B -
debounce 92 B -
DECORATORS 7.74 kB -
DEFAULT_DIAGNOSTIC_PREFIX 104 B -
defineFeatures 322 B -
defineManifest 455 B -
domScheduler 296 B -
DragService 1.94 kB -
ease 435 B -
easeInCirc 68 B -
easeInCubic 59 B -
easeInExpo 80 B -
easeInOutCirc 141 B -
easeInOutCubic 130 B -
easeInOutExpo 134 B -
easeInOutQuad 128 B -
easeInOutQuart 133 B -
easeInOutQuint 152 B -
easeInOutSine 151 B -
easeInQuad 63 B -
easeInQuart 61 B -
easeInQuint 62 B -
easeInSine 77 B -
easeLinear 49 B -
easeOutCirc 115 B -
easeOutCubic 103 B -
easeOutExpo 112 B -
easeOutQuad 103 B -
easeOutQuart 100 B -
easeOutQuint 103 B -
easeOutSine 121 B -
endsWith 88 B -
fold 156 B -
FRAMEWORK 16.75 kB -
fromMetaGlob 213 B -
fromWebpackContext 94 B -
getAncestorWhere 91 B -
getAncestorWhereUntil 119 B -
getClosestParent 184 B -
getComponentResolver 138 B -
getDirectChildren 201 B -
getInstanceFromElement 92 B -
getInstances 185 B -
getOffsetSizes 159 B -
getScopedGroups 95 B -
hasWindow 62 B -
HELPERS 2.69 kB -
historyPush 499 B -
historyReplace 503 B -
IDLE_TIMEOUT 53 B -
importOnInteraction 899 B -
importOnMediaQuery 236 B -
importWhenIdle 223 B -
importWhenPrefersMotion 275 B -
importWhenVisible 914 B -
inertiaFinalValue 142 B -
isArray 70 B -
isBoolean 78 B -
isDefined 86 B -
isDev 72 B -
isDirectChild 219 B -
isEmpty 207 B -
isEmptyString 93 B -
isFunction 72 B -
isNull 72 B -
isNumber 84 B -
isObject 105 B -
isString 86 B -
keyCodes 97 B -
KeyService 854 B -
lerp 57 B -
loadElement 169 B -
loadIframe 189 B -
loadImage 188 B -
loadLink 186 B -
loadScript 197 B -
LoadService 593 B -
localStorageProvider 715 B -
logTree 510 B -
lowerCase 60 B -
map 71 B -
matrix 106 B -
mean 91 B -
memo 100 B -
memoize 189 B -
memoryStorageProvider 607 B -
MutationService 799 B -
nextFrame 162 B -
nextMicrotask 111 B -
nextTick 134 B -
noop 39 B -
noopValue 49 B -
objectToURLSearchParams 302 B -
pascalCase 374 B -
PointerService 1.07 kB -
queryComponent 613 B -
queryComponentAll 616 B -
Queue 226 B -
RafService 956 B -
random 64 B -
randomInt 77 B -
randomItem 211 B -
readEagerTokens 186 B -
registerComponent 262 B -
registerComponents 300 B -
registerManifest 2.74 kB -
registerManifests 2.77 kB -
removeClass 222 B -
removeStyle 238 B -
ResizeService 1.01 kB -
round 56 B -
saveActiveElement 56 B -
ScrollService 1.28 kB -
scrollTo 2.31 kB -
SERVICES 4.01 kB -
sessionStorageProvider 712 B -
SmartQueue 411 B -
smoothTo 470 B -
snakeCase 374 B -
spring 115 B -
startsWith 87 B -
throttle 101 B -
toggleClass 225 B -
transform 288 B -
transition 914 B -
trapFocus 363 B -
tween 1.72 kB -
untrapFocus 45 B -
upperCase 54 B -
urlSearchParamsInHashProvider 537 B -
urlSearchParamsProvider 539 B -
useDrag 1.98 kB -
useKey 871 B -
useLoad 610 B -
useMutation 829 B -
usePointer 1.09 kB -
useRaf 963 B -
useResize 1.02 kB -
useScheduler 290 B -
useScroll 1.3 kB -
UTILS 9.63 kB -
version 47 B -
VISIBLE_ROOT_MARGIN 64 B -
wait 79 B -
withBreakpointManager 1.42 kB -
withBreakpointObserver 1.61 kB -
withDrag 2.09 kB -
withExtraConfig 134 B -
withFreezedOptions 140 B -
withGroup 399 B -
withIntersectionObserver 260 B -
withLeadingCharacters 88 B -
withLeadingSlash 107 B -
withMountOnMediaQuery 322 B -
withMountWhenInView 286 B -
withMountWhenPrefersMotion 355 B -
withMutation 959 B -
withName 81 B -
withoutLeadingCharacters 86 B -
withoutLeadingCharactersRecursive 124 B -
withoutLeadingSlash 93 B -
withoutTrailingCharacters 98 B -
withoutTrailingCharactersRecursive 129 B -
withoutTrailingSlash 103 B -
withRelativePointer 1.23 kB -
withResponsiveOptions 2.26 kB -
withScrolledInView 2.93 kB -
withTrailingCharacters 96 B -
withTrailingSlash 120 B -
wrap 93 B -

@codecov

codecov Bot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.17%. Comparing base (4cba5e3) to head (99eb6c4).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #750   +/-   ##
=======================================
  Coverage   97.17%   97.17%           
=======================================
  Files         170      170           
  Lines        4143     4143           
  Branches     1151     1152    +1     
=======================================
  Hits         4026     4026           
  Misses        106      106           
  Partials       11       11           
Flag Coverage Δ
eslint-plugin-js-toolkit 93.79% <ø> (ø)
js-toolkit 97.93% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq

codspeed-hq Bot commented Aug 1, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 127 untouched benchmarks


Comparing fix/mutation-scan-remount-and-swap-order (20b44b3) with main (a67c3cf)

Open in CodSpeed

@titouanmathis
titouanmathis force-pushed the fix/mutation-scan-remount-and-swap-order branch from ca96f1c to ee95feb Compare August 1, 2026 18:51
@titouanmathis titouanmathis changed the title Fix mutation-scan remount and same-batch swap order Codify: terminated components are permanent per DOM element Aug 1, 2026
@titouanmathis titouanmathis changed the title Codify: terminated components are permanent per DOM element Document the terminated marker contract and pin it with tests Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code Review

Risk: Low — The change documents the existing terminated-marker contract and adds regression coverage without changing runtime behavior; it is safe to merge.

The MR explains how automatic mount scanning handles terminated elements, including disconnect-triggered termination and the explicit remount escape hatch. It also adds focused tests covering same-node reinsertion, a positive mount control, replacement nodes, and explicit instantiation.


Review usage: 39,350 in (31,724 cached) / 865 out tokens — $0.0089 (openrouter/openai/gpt-5.6-luna, thinking: low)

Reviewed by @weareikko/code-review v0.9.5 for commit 99eb6c4.

Previous review runs

Previous run archived 2026-08-16T19:57:05Z

Code Review

Risk: Low — The change adds documentation and regression tests for the existing terminated-marker and automatic mount-scan contract, with no production behavior changes.

It documents how disconnect-driven termination prevents automatic remounting of the same DOM node and records the supported escape hatches. The tests cover both permanent skipping during automatic scans and explicit remounting through new Ctor(el).$mount().

No issues found.


Review usage: 8,931 in / 350 out tokens — $0.0066 (openrouter/openai/gpt-5.6-luna, thinking: low)

Reviewed by @weareikko/code-review v0.9.5 for commit 20b44b3.

titouanmathis and others added 2 commits August 16, 2026 19:55
Document and pin the existing contract: `$terminate()` is one-shot per
DOM element by design. A terminated element keeps its `'terminated'`
marker, so the document-wide mount scan skips it forever — re-inserting
the same node does not remount it. Replacing the element with a brand new
node is the supported way to mount a fresh instance.

This backs lazy/once components such as `withMountWhenInView`, which must
trigger exactly once when their element first enters the viewport and
must never re-trigger on the same element.

No behavior change: adds a doc comment on `$terminate()` and the mount
scan site, plus a regression test asserting both halves of the contract
(same-node re-insertion stays terminated; replacement remounts).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeZwHwo3d9rYsCxJUQqTep
The previous commit recorded two claims that do not hold.

1. It said the `'terminated'` marker "backs lazy/once components such as
   `withMountWhenInView`". It does not: `withMountWhenInView` calls
   `$mount()` on every enter and `$destroy()` on every leave, so it
   re-triggers on the same element by design and never calls
   `$terminate()`. Replaced with the rationale git history supports —
   commit `9bc6f838` changed `__base__.delete()` to
   `__base__.set(..., 'terminated')` so the marker survives and keeps the
   element excluded from `$children`, `$parent` and `queryComponent()`
   resolution, which already filtered on the `'terminated'` string.

2. It said "the only supported way to mount again is to replace the
   element with a brand new node". The constructor overwrites `__base__`
   unconditionally, so `new Ctor(el).$mount()` clears the marker and
   mounts a terminated node. The claim is now scoped to the automatic
   document-wide scan, with both escape hatches named.

Also record who actually calls `$terminate()`: the terminate pass of
`mutationCallback()` terminates any instance whose element is
disconnected, so users reach this state without calling `$terminate()`
themselves. The marker (2022) and that pass (2024, issue #552) were added
separately, so the combination is framed as a sharp edge with stated
workarounds, not as design intent.

Adds the public docs paragraph the contract was missing under
`$terminate()`, and hardens the test: a positive control element proves
the mount scan really ran during the re-insertion batch, a second test
pins the `new Ctor(el).$mount()` escape hatch, and both live in their own
`describe` block instead of the `addToRegistry` one.

No behavior change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114BLVFkrWWJAhmamS6NHB3
@titouanmathis
titouanmathis force-pushed the fix/mutation-scan-remount-and-swap-order branch from 20b44b3 to 99eb6c4 Compare August 16, 2026 19:56
@github-actions

Copy link
Copy Markdown

Export size

Bundled per export with peer dependencies left external, dynamic imports excluded and the output minified; sizes are gzipped.

✅ No export size changes.

Unchanged (388)

@studiometa/js-toolkit

Export Size (gzip) Diff
(barrel) 17.48 kB
AbstractService 598 B
Base 9.1 kB
ComponentLoader 2.31 kB
DEFAULT_DIAGNOSTIC_PREFIX 102 B
DragService 2.02 kB
IDLE_TIMEOUT 57 B
KeyService 935 B
LoadService 666 B
MutationService 849 B
PointerService 1.13 kB
RafService 1020 B
ResizeService 1.12 kB
ScrollService 1.36 kB
VISIBLE_ROOT_MARGIN 72 B
autoload 2.4 kB
closestComponent 419 B
composeManifests 119 B
createApp 996 B
defineFeatures 326 B
defineManifest 512 B
fromMetaGlob 228 B
fromWebpackContext 131 B
getClosestParent 197 B
getDirectChildren 202 B
getInstanceFromElement 125 B
getInstances 187 B
getScopedGroups 104 B
importOnInteraction 926 B
importOnMediaQuery 243 B
importWhenIdle 225 B
importWhenPrefersMotion 271 B
importWhenVisible 935 B
isDirectChild 218 B
logTree 551 B
queryComponent 594 B
queryComponentAll 601 B
readEagerTokens 201 B
registerComponent 305 B
registerComponents 356 B
registerManifest 2.87 kB
registerManifests 2.89 kB
useDrag 2.05 kB
useKey 943 B
useLoad 676 B
useMutation 876 B
usePointer 1.15 kB
useRaf 1 kB
useResize 1.13 kB
useScroll 1.36 kB
utils 10.08 kB
utils/Queue 291 B
utils/SmartQueue 473 B
utils/addClass 240 B
utils/addStyle 239 B
utils/animate 3.34 kB
utils/boundingRectToCircle 206 B
utils/cache 208 B
utils/camelCase 405 B
utils/clamp 98 B
utils/clamp01 114 B
utils/collideCircleCircle 129 B
utils/collideCircleRect 192 B
utils/collidePointCircle 128 B
utils/collidePointRect 122 B
utils/collideRectRect 128 B
utils/createEaseInOut 123 B
utils/createEaseOut 91 B
utils/createElement 635 B
utils/createLocalStorage 1.32 kB
utils/createLocalStorageProvider 296 B
utils/createMemoryStorageProvider 174 B
utils/createNoopProvider 128 B
utils/createRange 115 B
utils/createSessionStorage 1.32 kB
utils/createSessionStorageProvider 288 B
utils/createStorage 1.3 kB
utils/createUrlSearchParamsInHashProvider 461 B
utils/createUrlSearchParamsInHashStorage 1.35 kB
utils/createUrlSearchParamsProvider 429 B
utils/createUrlSearchParamsStorage 1.34 kB
utils/damp 106 B
utils/dashCase 404 B
utils/debounce 122 B
utils/domScheduler 310 B
utils/ease 519 B
utils/easeInCirc 285 B
utils/easeInCubic 287 B
utils/easeInExpo 286 B
utils/easeInOutCirc 288 B
utils/easeInOutCubic 289 B
utils/easeInOutExpo 288 B
utils/easeInOutQuad 288 B
utils/easeInOutQuart 289 B
utils/easeInOutQuint 289 B
utils/easeInOutSine 288 B
utils/easeInQuad 285 B
utils/easeInQuart 286 B
utils/easeInQuint 286 B
utils/easeInSine 285 B
utils/easeLinear 77 B
utils/easeOutCirc 286 B
utils/easeOutCubic 288 B
utils/easeOutExpo 286 B
utils/easeOutQuad 286 B
utils/easeOutQuart 286 B
utils/easeOutQuint 286 B
utils/easeOutSine 286 B
utils/endsWith 128 B
utils/fold 168 B
utils/getAncestorWhere 123 B
utils/getAncestorWhereUntil 148 B
utils/getComponentResolver 140 B
utils/getOffsetSizes 194 B
utils/hasWindow 88 B
utils/historyPush 524 B
utils/historyReplace 526 B
utils/inertiaFinalValue 169 B
utils/isArray 63 B
utils/isBoolean 78 B
utils/isDefined 75 B
utils/isDev 78 B
utils/isEmpty 206 B
utils/isEmptyString 108 B
utils/isFunction 79 B
utils/isNull 68 B
utils/isNumber 91 B
utils/isObject 108 B
utils/isString 77 B
utils/keyCodes 122 B
utils/lerp 84 B
utils/loadElement 220 B
utils/loadIframe 241 B
utils/loadImage 241 B
utils/loadLink 237 B
utils/loadScript 251 B
utils/localStorageProvider 839 B
utils/lowerCase 404 B
utils/map 93 B
utils/matrix 136 B
utils/mean 126 B
utils/memo 130 B
utils/memoize 228 B
utils/memoryStorageProvider 843 B
utils/nextFrame 179 B
utils/nextMicrotask 133 B
utils/nextTick 148 B
utils/noop 62 B
utils/noopValue 76 B
utils/objectToURLSearchParams 322 B
utils/pascalCase 407 B
utils/random 93 B
utils/randomInt 113 B
utils/randomItem 234 B
utils/removeClass 242 B
utils/removeStyle 243 B
utils/round 95 B
utils/saveActiveElement 92 B
utils/scrollTo 2.31 kB
utils/sessionStorageProvider 838 B
utils/smoothTo 476 B
utils/snakeCase 406 B
utils/spring 154 B
utils/startsWith 125 B
utils/throttle 125 B
utils/toggleClass 242 B
utils/transform 347 B
utils/transition 1010 B
utils/trapFocus 441 B
utils/tween 1.72 kB
utils/untrapFocus 120 B
utils/upperCase 404 B
utils/urlSearchParamsInHashProvider 845 B
utils/urlSearchParamsProvider 839 B
utils/useScheduler 309 B
utils/wait 103 B
utils/withLeadingCharacters 135 B
utils/withLeadingSlash 142 B
utils/withTrailingCharacters 135 B
utils/withTrailingSlash 142 B
utils/withoutLeadingCharacters 122 B
utils/withoutLeadingCharactersRecursive 165 B
utils/withoutLeadingSlash 133 B
utils/withoutTrailingCharacters 122 B
utils/withoutTrailingCharactersRecursive 165 B
utils/withoutTrailingSlash 133 B
utils/wrap 122 B
version 56 B
withBreakpointManager 1.54 kB
withBreakpointObserver 1.71 kB
withDrag 2.18 kB
withExtraConfig 163 B
withFreezedOptions 187 B
withGroup 455 B
withIntersectionObserver 303 B
withMountOnMediaQuery 393 B
withMountWhenInView 347 B
withMountWhenPrefersMotion 431 B
withMutation 1010 B
withName 109 B
withRelativePointer 1.29 kB
withResponsiveOptions 2.4 kB
withScrolledInView 3.05 kB

@studiometa/js-toolkit-v4

Export Size (gzip) Diff
(barrel) 20.87 kB
BREAKPOINTS 776 B
Base 8.1 kB
DIAGNOSTICS 642 B
DRAG_MODES 162 B
EVENTS 155 B
MOUNT_ATTRIBUTE 69 B
SWAP_MODES 129 B
children 244 B
component 10.84 kB
createContext 472 B
createFallbackProvider 1.34 kB
createGroup 1.06 kB
createLocalStorage 2.34 kB
createLocalStorageProvider 1.23 kB
createMemoryStorageProvider 1.23 kB
createService 630 B
createServiceMixin 509 B
createSessionStorage 2.34 kB
createSessionStorageProvider 1.23 kB
createStorage 2.32 kB
createUrlSearchParamsInHashProvider 1.23 kB
createUrlSearchParamsInHashStorage 2.36 kB
createUrlSearchParamsProvider 1.23 kB
createUrlSearchParamsStorage 2.36 kB
defaultScheduler 1.5 kB
defineManifest 983 B
domUpdate 1.23 kB
emitExtendable 1.09 kB
fromMetaGlob 203 B
fromWebpackContext 131 B
getBreakpoints 776 B
getInstances 2.81 kB
inject 176 B
injectContext 675 B
injectContextSync 634 B
jsonSerializer 95 B
localStorageProvider 1.22 kB
memoryStorageProvider 1.23 kB
nextFrame 115 B
on 8.43 kB
perTarget 176 B
provide 182 B
provideContext 704 B
provideRootContext 748 B
read 126 B
registerComponent 10.47 kB
registerComponents 10.49 kB
registerManifest 10.56 kB
sessionStorageProvider 1.22 kB
setBreakpoints 805 B
signal 920 B
subscribeContext 1.45 kB
swap 2.63 kB
toggle 176 B
until 172 B
urlSearchParamsInHashProvider 1.22 kB
urlSearchParamsProvider 1.22 kB
useBreakpoint 1.44 kB
useDrag 3.22 kB
useInView 1.31 kB
useMediaQuery 1.05 kB
useMutation 1.29 kB
usePointer 1.72 kB
usePrefersReducedMotion 1.08 kB
useRaf 1.93 kB
useResize 1.3 kB
useScroll 2.54 kB
useScrollProgress 3.51 kB
useWindowScroll 2.52 kB
useWindowSize 1.3 kB
utils 8.65 kB
utils/DEFAULT_DAMP_FACTOR 109 B
utils/INERTIA_FRAME 97 B
utils/MAX_SPRING_RATIO 100 B
utils/SCROLL_AXES 100 B
utils/TRANSFORM_PROPS 137 B
utils/TRANSITION_OPTIONS 132 B
utils/camelCase 449 B
utils/capitalize 119 B
utils/clamp 133 B
utils/clamp01 149 B
utils/clampDampFactor 157 B
utils/createEaseInOut 120 B
utils/createEaseOut 91 B
utils/createElement 638 B
utils/createRange 205 B
utils/damp 211 B
utils/debounce 121 B
utils/decayOver 162 B
utils/deepmerge 312 B
utils/easeInCirc 94 B
utils/easeInCubic 81 B
utils/easeInExpo 97 B
utils/easeInOutCirc 150 B
utils/easeInOutCubic 141 B
utils/easeInOutExpo 150 B
utils/easeInOutQuad 139 B
utils/easeInOutQuart 140 B
utils/easeInOutQuint 140 B
utils/easeInOutSine 156 B
utils/easeInQuad 80 B
utils/easeInQuart 81 B
utils/easeInQuint 81 B
utils/easeInSine 104 B
utils/easeLinear 77 B
utils/easeOutCirc 121 B
utils/easeOutCubic 111 B
utils/easeOutExpo 124 B
utils/easeOutQuad 110 B
utils/easeOutQuart 112 B
utils/easeOutQuint 111 B
utils/easeOutSine 132 B
utils/enterTransition 679 B
utils/fold 200 B
utils/getOffsetSizes 268 B
utils/historyPush 380 B
utils/historyReplace 381 B
utils/inertiaDecay 199 B
utils/inertiaFinalValue 187 B
utils/inertiaStep 232 B
utils/inertiaTimeConstant 178 B
utils/isBoolean 90 B
utils/isDefined 87 B
utils/isFunction 86 B
utils/isNull 78 B
utils/isNumber 103 B
utils/isObject 115 B
utils/isString 89 B
utils/kebabCase 421 B
utils/leaveTransition 679 B
utils/lerp 120 B
utils/loadImage 245 B
utils/loadLink 776 B
utils/loadScript 697 B
utils/lowerCase 84 B
utils/map 128 B
utils/matrix 150 B
utils/mean 147 B
utils/memo 217 B
utils/noop 62 B
utils/noopValue 76 B
utils/objectToURLSearchParams 253 B
utils/pascalCase 434 B
utils/random 93 B
utils/randomInt 132 B
utils/randomItem 163 B
utils/round 130 B
utils/saveActiveElement 571 B
utils/scrollTo 1.72 kB
utils/selectorFor 2.72 kB
utils/setClassesOrStyles 218 B
utils/smoothTo 2.56 kB
utils/snakeCase 421 B
utils/spring 343 B
utils/throttle 151 B
utils/transform 286 B
utils/transition 577 B
utils/trapFocus 717 B
utils/untrapFocus 587 B
utils/upperCase 84 B
utils/wait 103 B
utils/withLeadingCharacters 142 B
utils/withLeadingSlash 152 B
utils/withTrailingCharacters 143 B
utils/withTrailingSlash 153 B
utils/withoutLeadingCharacters 127 B
utils/withoutLeadingCharactersRecursive 144 B
utils/withoutLeadingSlash 138 B
utils/withoutTrailingCharacters 129 B
utils/withoutTrailingCharactersRecursive 147 B
utils/withoutTrailingSlash 140 B
utils/wrap 154 B
viewTransition 1.66 kB
watchAttributes 1.98 kB
whenDOMSettled 2.31 kB
withDrag 3.61 kB
withInView 1.76 kB
withMutation 1.78 kB
withPointer 2.11 kB
withRaf 2.31 kB
withResize 1.7 kB
withScroll 2.93 kB
withScrollProgress 3.94 kB
write 124 B

@github-actions

Copy link
Copy Markdown

v3 mount benchmarks

Base and head measured on this runner, alternating over 3 rounds each; every value is the median of the round medians. Running both sides on one machine is what removes cross-machine noise — a cached baseline from another runner would put it back.

A move under 25%, or on a benchmark under 5 ms, is not reported as a change: it is inside the measured noise of a shared runner.

No benchmark moved beyond the noise floor.

Within noise (10)
Group Benchmark Base Head us / component Change
destroy 1000 flat components — v3 v3 — destroy 15.0 ms 14.5 ms 14.50 -3.3%
destroy 1000 flat components — v4 v4 — destroy 2.80 ms 2.70 ms 2.70 -3.6%
swap 1000 components — v3 v3 — control 0.20 ms 0.20 ms 0.20 0.0%
swap 1000 components — v3 v3 — flat 39.4 ms 34.3 ms 34.30 -12.9%
swap 1000 components — v3 v3 — nested 43.6 ms 43.8 ms 43.80 +0.5%
swap 1000 components — v3 v3 — realistic 123.2 ms 123.9 ms 123.90 +0.6%
swap 1000 components — v4 v4 — control 2.00 ms 2.00 ms 2.00 0.0%
swap 1000 components — v4 v4 — flat 14.2 ms 14.2 ms 14.20 0.0%
swap 1000 components — v4 v4 — nested 13.9 ms 13.1 ms 13.10 -5.8%
swap 1000 components — v4 v4 — realistic 76.3 ms 72.2 ms 72.20 -5.4%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant