From 04cbd0c7856a7e12462f9072e5b737b3ccdee5e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=B6=E8=BF=9C=E6=96=B9?= Date: Sun, 28 Apr 2024 20:27:57 +0800 Subject: [PATCH 1/3] feat(effectScope): add onDispose method --- packages/reactivity/__tests__/effectScope.spec.ts | 11 +++++++++++ packages/reactivity/src/effectScope.ts | 11 ++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/reactivity/__tests__/effectScope.spec.ts b/packages/reactivity/__tests__/effectScope.spec.ts index 4d83d867cf7..e46d65baea2 100644 --- a/packages/reactivity/__tests__/effectScope.spec.ts +++ b/packages/reactivity/__tests__/effectScope.spec.ts @@ -295,4 +295,15 @@ describe('reactivity/effect/scope', () => { expect(getCurrentScope()).toBe(parentScope) }) }) + + it('should register a cleanup function to be called when the effect scope is stopped', () => { + const spy = vi.fn() + + const scope = effectScope() + scope.onDispose(spy) + + expect(spy).toHaveBeenCalledTimes(0) + scope.stop() + expect(spy).toHaveBeenCalledTimes(1) + }) }) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index bc45f8491b8..99d30b70de5 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -105,6 +105,15 @@ export class EffectScope { this._active = false } } + + /** + * Registers a cleanup function to be called when the effect scope is stopped. + * + * @param {() => void} fn - The cleanup function to be registered. + */ + onDispose(fn: () => void) { + this.cleanups.push(fn) + } } /** @@ -138,7 +147,7 @@ export function getCurrentScope() { */ export function onScopeDispose(fn: () => void, failSilently = false) { if (activeEffectScope) { - activeEffectScope.cleanups.push(fn) + activeEffectScope.onDispose(fn) } else if (__DEV__ && !failSilently) { warn( `onScopeDispose() is called when there is no active effect scope` + From 3d4bac88f80daa6a0476a712481d0da5b96c3622 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 16 Aug 2024 20:36:15 +0800 Subject: [PATCH 2/3] workflow: pass along commit in ecosystem-ci-trigger [ci skip] --- .github/workflows/ecosystem-ci-trigger.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ecosystem-ci-trigger.yml b/.github/workflows/ecosystem-ci-trigger.yml index 25adf7c85f4..fdd40600847 100644 --- a/.github/workflows/ecosystem-ci-trigger.yml +++ b/.github/workflows/ecosystem-ci-trigger.yml @@ -56,7 +56,8 @@ jobs: return { num: context.issue.number, branchName: pr.head.ref, - repo: pr.head.repo.full_name + repo: pr.head.repo.full_name, + commit: pr.head.sha } - uses: actions/github-script@v7 id: trigger @@ -81,5 +82,6 @@ jobs: branchName: prData.branchName, repo: prData.repo, suite: suite === '' ? '-' : suite + commit: prData.commit } }) From b9f84dae8505cc743577cf1321dd2e045a2d73e6 Mon Sep 17 00:00:00 2001 From: Michael Brevard Date: Wed, 18 Sep 2024 10:44:23 +0300 Subject: [PATCH 3/3] perf(hydration): avoid observer if element is in viewport (#11639) --- .../runtime-core/src/hydrationStrategies.ts | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/runtime-core/src/hydrationStrategies.ts b/packages/runtime-core/src/hydrationStrategies.ts index 51200fc1c34..791ca9e5254 100644 --- a/packages/runtime-core/src/hydrationStrategies.ts +++ b/packages/runtime-core/src/hydrationStrategies.ts @@ -26,6 +26,16 @@ export const hydrateOnIdle: HydrationStrategyFactory = return () => cancelIdleCallback(id) } +function elementIsVisibleInViewport(el: Element) { + const { top, left, bottom, right } = el.getBoundingClientRect() + // eslint-disable-next-line no-restricted-globals + const { innerHeight, innerWidth } = window + return ( + ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) && + ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth)) + ) +} + export const hydrateOnVisible: HydrationStrategyFactory< IntersectionObserverInit > = opts => (hydrate, forEach) => { @@ -37,7 +47,14 @@ export const hydrateOnVisible: HydrationStrategyFactory< break } }, opts) - forEach(el => ob.observe(el)) + forEach(el => { + if (elementIsVisibleInViewport(el)) { + hydrate() + ob.disconnect() + return false + } + ob.observe(el) + }) return () => ob.disconnect() } @@ -85,14 +102,20 @@ export const hydrateOnInteraction: HydrationStrategyFactory< return teardown } -export function forEachElement(node: Node, cb: (el: Element) => void): void { +export function forEachElement( + node: Node, + cb: (el: Element) => void | false, +): void { // fragment if (isComment(node) && node.data === '[') { let depth = 1 let next = node.nextSibling while (next) { if (next.nodeType === DOMNodeTypes.ELEMENT) { - cb(next as Element) + const result = cb(next as Element) + if (result === false) { + break + } } else if (isComment(next)) { if (next.data === ']') { if (--depth === 0) break