From f5c89e8e4a52e34acffc8a5696abb4305959e346 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Fri, 25 Oct 2024 12:43:56 +0200 Subject: [PATCH 1/4] Removing will-change --- .../src/motion/__tests__/ssr.test.tsx | 4 +- .../src/motion/utils/use-visual-state.ts | 33 +---- .../framer-motion/src/render/VisualElement.ts | 6 - .../src/render/html/HTMLVisualElement.ts | 2 - .../src/render/html/config-motion.ts | 1 - .../render/html/utils/scrape-motion-values.ts | 8 -- .../__tests__/will-change.ssr.test.tsx | 116 ++++++++++++++++++ .../value/use-will-change/add-will-change.ts | 2 - 8 files changed, 120 insertions(+), 52 deletions(-) create mode 100644 packages/framer-motion/src/value/use-will-change/__tests__/will-change.ssr.test.tsx diff --git a/packages/framer-motion/src/motion/__tests__/ssr.test.tsx b/packages/framer-motion/src/motion/__tests__/ssr.test.tsx index 7fdd2a239e..1fa5093df5 100644 --- a/packages/framer-motion/src/motion/__tests__/ssr.test.tsx +++ b/packages/framer-motion/src/motion/__tests__/ssr.test.tsx @@ -146,7 +146,7 @@ function runTests(render: (components: any) => string) { ) expect(div).toBe( - '
' + '
' ) }) @@ -165,7 +165,7 @@ function runTests(render: (components: any) => string) { ) expect(customElement).toBe( - '' + '' ) }) diff --git a/packages/framer-motion/src/motion/utils/use-visual-state.ts b/packages/framer-motion/src/motion/utils/use-visual-state.ts index 13d8086615..92f39667ef 100644 --- a/packages/framer-motion/src/motion/utils/use-visual-state.ts +++ b/packages/framer-motion/src/motion/utils/use-visual-state.ts @@ -15,7 +15,6 @@ import { isVariantNode as checkIsVariantNode, } from "../../render/utils/is-controlling-variants" import { TargetAndTransition } from "../../types" -import { getWillChangeName } from "../../value/use-will-change/get-will-change-name" export interface VisualState { renderState: RenderState @@ -29,7 +28,6 @@ export type UseVisualState = ( ) => VisualState export interface UseVisualStateConfig { - applyWillChange?: boolean scrapeMotionValuesFromProps: ScrapeMotionValuesFromProps createRenderState: () => RenderState onMount?: ( @@ -41,22 +39,19 @@ export interface UseVisualStateConfig { function makeState( { - applyWillChange = false, scrapeMotionValuesFromProps, createRenderState, onMount, }: UseVisualStateConfig, props: MotionProps, context: MotionContextProps, - presenceContext: PresenceContextProps | null, - isStatic: boolean + presenceContext: PresenceContextProps | null ) { const state: VisualState = { latestValues: makeLatestValues( props, context, presenceContext, - isStatic ? false : applyWillChange, scrapeMotionValuesFromProps ), renderState: createRenderState(), @@ -74,8 +69,7 @@ export const makeUseVisualState = (props: MotionProps, isStatic: boolean): VisualState => { const context = useContext(MotionContext) const presenceContext = useContext(PresenceContext) - const make = () => - makeState(config, props, context, presenceContext, isStatic) + const make = () => makeState(config, props, context, presenceContext) return isStatic ? make() : useConstant(make) } @@ -102,13 +96,9 @@ function makeLatestValues( props: MotionProps, context: MotionContextProps, presenceContext: PresenceContextProps | null, - shouldApplyWillChange: boolean, scrapeMotionValues: ScrapeMotionValuesFromProps ) { const values: ResolvedValues = {} - const willChange = new Set() - const applyWillChange = - shouldApplyWillChange && props.style?.willChange === undefined const motionValues = scrapeMotionValues(props, {}) for (const key in motionValues) { @@ -168,24 +158,5 @@ function makeLatestValues( }) } - // Add animating values to will-change - if (applyWillChange) { - if (animate && initial !== false && !isAnimationControls(animate)) { - forEachDefinition(props, animate, (target) => { - for (const name in target) { - const memberName = getWillChangeName(name) - - if (memberName) { - willChange.add(memberName) - } - } - }) - } - - if (willChange.size) { - values.willChange = Array.from(willChange).join(",") - } - } - return values } diff --git a/packages/framer-motion/src/render/VisualElement.ts b/packages/framer-motion/src/render/VisualElement.ts index d05c8cfabd..da30839aa0 100644 --- a/packages/framer-motion/src/render/VisualElement.ts +++ b/packages/framer-motion/src/render/VisualElement.ts @@ -135,12 +135,6 @@ export abstract class VisualElement< projection?: IProjectionNode ): void - /** - * If true, will-change will be applied to the element. Only HTMLVisualElements - * currently support this. - */ - applyWillChange = false - /** * If the component child is provided as a motion value, handle subscriptions * with the renderer-specific VisualElement. diff --git a/packages/framer-motion/src/render/html/HTMLVisualElement.ts b/packages/framer-motion/src/render/html/HTMLVisualElement.ts index c538de2787..0de27f45e7 100644 --- a/packages/framer-motion/src/render/html/HTMLVisualElement.ts +++ b/packages/framer-motion/src/render/html/HTMLVisualElement.ts @@ -26,8 +26,6 @@ export class HTMLVisualElement extends DOMVisualElement< > { type = "html" - applyWillChange = true - readValueFromInstance( instance: HTMLElement, key: string diff --git a/packages/framer-motion/src/render/html/config-motion.ts b/packages/framer-motion/src/render/html/config-motion.ts index 06c3ec2794..d13545c637 100644 --- a/packages/framer-motion/src/render/html/config-motion.ts +++ b/packages/framer-motion/src/render/html/config-motion.ts @@ -8,7 +8,6 @@ export const htmlMotionConfig: Partial< MotionComponentConfig > = { useVisualState: makeUseVisualState({ - applyWillChange: true, scrapeMotionValuesFromProps, createRenderState: createHtmlRenderState, }), diff --git a/packages/framer-motion/src/render/html/utils/scrape-motion-values.ts b/packages/framer-motion/src/render/html/utils/scrape-motion-values.ts index a39d58a157..d971f5886e 100644 --- a/packages/framer-motion/src/render/html/utils/scrape-motion-values.ts +++ b/packages/framer-motion/src/render/html/utils/scrape-motion-values.ts @@ -23,13 +23,5 @@ export function scrapeMotionValuesFromProps( } } - /** - * If the willChange style has been manually set as a string, set - * applyWillChange to false to prevent it from automatically being applied. - */ - if (visualElement && style && typeof style.willChange === "string") { - visualElement.applyWillChange = false - } - return newValues } diff --git a/packages/framer-motion/src/value/use-will-change/__tests__/will-change.ssr.test.tsx b/packages/framer-motion/src/value/use-will-change/__tests__/will-change.ssr.test.tsx new file mode 100644 index 0000000000..ad352aa0d6 --- /dev/null +++ b/packages/framer-motion/src/value/use-will-change/__tests__/will-change.ssr.test.tsx @@ -0,0 +1,116 @@ +import { renderToString, renderToStaticMarkup } from "react-dom/server" +import { MotionConfig, motion } from "../../../" +import { motionValue } from "../../../value" + +function runTests(render: (components: any) => string) { + test("will-change not applied", () => { + const div = render( + + ) + + expect(div).toBe( + `
` + ) + }) + + test("will-change not set in static mode", () => { + const div = render( + + + + ) + + expect(div).toBe( + `
` + ) + }) + + test("will-change manually set", () => { + const div = render( + + ) + + expect(div).toBe( + `
` + ) + }) + + test("will-change manually set without animated values", () => { + const div = render() + + expect(div).toBe(`
`) + }) + + test("will-change not set without animated values", () => { + const div = render() + + expect(div).toBe(`
`) + }) + + test("Externally defined MotionValues not automatically added to will-change", () => { + const opacity = motionValue(0.5) + const div = render() + + expect(div).toBe(`
`) + }) + + test("will-change manually set by MotionValue", () => { + const willChange = motionValue("opacity") + const div = render( + + ) + + expect(div).toBe( + `
` + ) + }) + + test("will-change correctly not applied when isStatic", () => { + const div = render( + + + + ) + + expect(div).toBe( + `
` + ) + }) +} + +describe("render", () => { + runTests(renderToString) +}) + +describe("renderToStaticMarkup", () => { + runTests(renderToStaticMarkup) +}) diff --git a/packages/framer-motion/src/value/use-will-change/add-will-change.ts b/packages/framer-motion/src/value/use-will-change/add-will-change.ts index 85a75e1de7..6edae115ed 100644 --- a/packages/framer-motion/src/value/use-will-change/add-will-change.ts +++ b/packages/framer-motion/src/value/use-will-change/add-will-change.ts @@ -5,8 +5,6 @@ export function addValueToWillChange( visualElement: VisualElement, key: string ) { - if (!visualElement.applyWillChange) return - const willChange = visualElement.getValue("willChange") /** From f4c72c876f2d7cfd706e73f327ef32f05053010c Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Fri, 25 Oct 2024 12:45:18 +0200 Subject: [PATCH 2/4] Reducing bundle size --- packages/framer-motion/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/framer-motion/package.json b/packages/framer-motion/package.json index 45b9cb8cb0..1618f36cc1 100644 --- a/packages/framer-motion/package.json +++ b/packages/framer-motion/package.json @@ -108,15 +108,15 @@ "bundlesize": [ { "path": "./dist/size-rollup-motion.js", - "maxSize": "33.96 kB" + "maxSize": "33.8 kB" }, { "path": "./dist/size-rollup-m.js", - "maxSize": "5.9 kB" + "maxSize": "5.7 kB" }, { "path": "./dist/size-rollup-dom-animation.js", - "maxSize": "17 kB" + "maxSize": "16.95 kB" }, { "path": "./dist/size-rollup-dom-max.js", @@ -124,7 +124,7 @@ }, { "path": "./dist/size-rollup-animate.js", - "maxSize": "18 kB" + "maxSize": "17.9 kB" }, { "path": "./dist/size-rollup-scroll.js", From 5507ae346a5c86157abaa93b6d8cad08753cb89e Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Fri, 25 Oct 2024 12:48:06 +0200 Subject: [PATCH 3/4] Refactor --- .../src/motion/utils/use-visual-state.ts | 68 ++++++++----------- 1 file changed, 27 insertions(+), 41 deletions(-) diff --git a/packages/framer-motion/src/motion/utils/use-visual-state.ts b/packages/framer-motion/src/motion/utils/use-visual-state.ts index 92f39667ef..326059c13b 100644 --- a/packages/framer-motion/src/motion/utils/use-visual-state.ts +++ b/packages/framer-motion/src/motion/utils/use-visual-state.ts @@ -14,7 +14,6 @@ import { isControllingVariants as checkIsControllingVariants, isVariantNode as checkIsVariantNode, } from "../../render/utils/is-controlling-variants" -import { TargetAndTransition } from "../../types" export interface VisualState { renderState: RenderState @@ -74,24 +73,6 @@ export const makeUseVisualState = return isStatic ? make() : useConstant(make) } -function forEachDefinition( - props: MotionProps, - definition: MotionProps["animate"] | MotionProps["initial"], - callback: ( - target: TargetAndTransition, - transitionEnd: ResolvedValues - ) => void -) { - const list = Array.isArray(definition) ? definition : [definition] - for (let i = 0; i < list.length; i++) { - const resolved = resolveVariantFromProps(props, list[i] as any) - if (resolved) { - const { transitionEnd, transition, ...target } = resolved - callback(target, transitionEnd as ResolvedValues) - } - } -} - function makeLatestValues( props: MotionProps, context: MotionContextProps, @@ -131,31 +112,36 @@ function makeLatestValues( typeof variantToSet !== "boolean" && !isAnimationControls(variantToSet) ) { - forEachDefinition(props, variantToSet, (target, transitionEnd) => { - for (const key in target) { - let valueTarget = target[key as keyof typeof target] - - if (Array.isArray(valueTarget)) { - /** - * Take final keyframe if the initial animation is blocked because - * we want to initialise at the end of that blocked animation. - */ - const index = isInitialAnimationBlocked - ? valueTarget.length - 1 - : 0 - valueTarget = valueTarget[index] + const list = Array.isArray(variantToSet) ? variantToSet : [variantToSet] + for (let i = 0; i < list.length; i++) { + const resolved = resolveVariantFromProps(props, list[i] as any) + if (resolved) { + const { transitionEnd, transition, ...target } = resolved + for (const key in target) { + let valueTarget = target[key as keyof typeof target] + + if (Array.isArray(valueTarget)) { + /** + * Take final keyframe if the initial animation is blocked because + * we want to initialise at the end of that blocked animation. + */ + const index = isInitialAnimationBlocked + ? valueTarget.length - 1 + : 0 + valueTarget = valueTarget[index] + } + + if (valueTarget !== null) { + values[key] = valueTarget as string | number + } } - - if (valueTarget !== null) { - values[key] = valueTarget as string | number + for (const key in transitionEnd) { + values[key] = transitionEnd[ + key as keyof typeof transitionEnd + ] as string | number } } - for (const key in transitionEnd) { - values[key] = transitionEnd[ - key as keyof typeof transitionEnd - ] as string | number - } - }) + } } return values From 0325534927285949c6ea39bf6a547407eeb4782b Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Fri, 25 Oct 2024 13:24:29 +0200 Subject: [PATCH 4/4] Updating test --- packages/framer-motion/src/motion/__tests__/variant.test.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/framer-motion/src/motion/__tests__/variant.test.tsx b/packages/framer-motion/src/motion/__tests__/variant.test.tsx index fc69f46513..e9b20a3b6e 100644 --- a/packages/framer-motion/src/motion/__tests__/variant.test.tsx +++ b/packages/framer-motion/src/motion/__tests__/variant.test.tsx @@ -817,11 +817,7 @@ describe("animate prop as variant", () => { const promise = new Promise((resolve) => { let latest = {} - let frameCount = 0 - const onUpdate = (l: { [key: string]: number | string }) => { - frameCount++ - if (frameCount === 2) expect(l.willChange).toBe("transform") latest = l } @@ -842,7 +838,6 @@ describe("animate prop as variant", () => { }) return expect(promise).resolves.toEqual({ - willChange: "transform", x: 100, y: 100, })