dotlottie-web icon indicating copy to clipboard operation
dotlottie-web copied to clipboard

dotlottie-react workerOptions prop and dotlottie-web worker bug in safari

Open sevilladiego8 opened this issue 7 months ago • 5 comments

Overview 1 - dotlottie-react workerOptions

After testing various lottie animations for the web during this month, I decided to try different player options to see the pros and cons between them. I ended up running into dotlottie-web and the web worker feature (which prevents CPU overload), tested the worker in crhome/opera/edge (crhomiun based browsers) and firefox, and it works well. CPU looks pretty well!

NOTE: Altough I am using React^19.0.0 I decided to use dotlottie-web instead of dotlottie-react because dotlottie-react presents a very high CPU usage (even with simple animations) which slows down the performance of my browser/my PC overall and thus it is not a good option for my use case.

Here is a comparison table between the two options when hovering over a lottie animation, using Chrome Performance Monitor:

dotlottie-react dotlottie-web + worker
CPU Usage Image Image

Question 1

  1. Reading dotlottie-react docs and also following past issues https://github.com/LottieFiles/dotlottie-web/issues/203 I was not able to find a prop which enables the usage of a web worker to prevent the CPU overload. Am I missing something? or is this feature not implemented for the dotlottie-react wrapper?

It would be great to have a prop like workerOptions to enable it's usage and customization with dotlottie-react:

   <DotLottieReact
      src={src}
      className={className}
      speed={speed}
      loop={loop}
      autoplay={autoplay}
      dotLottieRefCallback={dotLottieRefCallback}
      layout={layout}
      useFrameInterpolation={false} 
      workerOptions={{
           enable: true,
           absoluteUrlPath: 'someUrl',
           ...otherOptions
     }}
    />

Overview 2 - worker issue in safari

The web worker works like a charm in chromium based browsers and also works for firefox, however for safari, dotlottie-web custom components break on the initial load due to the following error:

[Error] Unhandled Promise Rejection: TypeError: this._canvas.transferControlToOffscreen is not a function. (In 'this._canvas.transferControlToOffscreen()', 'this._canvas.transferControlToOffscreen' is undefined)
	(anonymous function) (@lottiefiles_dotlottie-web.js:38)
	Promise
	E (@lottiefiles_dotlottie-web.js:24)
	Y2 (@lottiefiles_dotlottie-web.js:2150:191)
	(anonymous function) (DotLottieWorkerComp.tsx:91)
	react-stack-bottom-frame (react-dom_client.js:17478)
	runWithFiberInDEV (react-dom_client.js:1487)
	commitHookEffectListMount (react-dom_client.js:8460:140)
	commitHookPassiveMountEffects (react-dom_client.js:8518:86)
	commitPassiveMountOnFiber (react-dom_client.js:9887)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9984)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9881)
	recursivelyTraversePassiveMountEffects (react-dom_client.js:9868)
	commitPassiveMountOnFiber (react-dom_client.js:9899)
	flushPassiveEffects (react-dom_client.js:11302)
	performSyncWorkOnRoot (react-dom_client.js:11632)
	flushSyncWorkAcrossRoots_impl (react-dom_client.js:11536:144)
	flushSpawnedWork (react-dom_client.js:11254)
	commitRoot (react-dom_client.js:11081)
	commitRootWhenReady (react-dom_client.js:10512)
	performWorkOnRoot (react-dom_client.js:10457)
	performWorkOnRootViaSchedulerTask (react-dom_client.js:11623)
	performWorkUntilDeadline (react-dom_client.js:36)

NOTE: i also noticed a similar error happens in firefox when having a lot of browser tabs opened. I remember i saw a memory issue with the worker on firefox too, however i was not able to reproduce it again. It fails on firefox sometimes, not really sure if it's happening to me only.

My dotlottie-web component (using the web worker) implementation is very similar to the patch added in this comment: https://github.com/LottieFiles/dotlottie-web/issues/326#issuecomment-2439925628

...

Consuming repo

  • dotlottie-web -> "@lottiefiles/dotlottie-web": "^0.44.0" https://github.com/LottieFiles/dotlottie-web/blob/main/packages/web/README.md
  • dotlottie-react -> "@lottiefiles/dotlottie-react": "^0.13.5" https://github.com/LottieFiles/dotlottie-web/blob/main/packages/react/README.md

Browser versions

firefox - 138.0.4 (64-bit) safari - ~16 , AppleWebKit/605.1.15 (KHTML, like Gecko)

lottie animation for testing purposes

I created this animation for testing purposes using some of the lottie web features:

...

Labels

  • [x] Add the Type: Bug label to this issue.

References

  • Web worker - https://developers.lottiefiles.com/docs/dotlottie-player/dotlottie-web/worker/
  • https://github.com/LottieFiles/dotlottie-web

Last but not least.... THANKS SO MUCH for the great work dotlottie-web dev team! ⭐ 💯

sevilladiego8 avatar May 21 '25 20:05 sevilladiego8

@sevilladiego8 Thanks so much for the detailed report!

yes, dotlottie-react does support web workers, but it requires using the DotLottieWorkerReact component instead of the default DotLottieReact. You can import it like this:

import { DotLottieWorkerReact } from "@lottiefiles/dotlottie-react";

This component wraps dotlottie-web with the worker enabled under the hood, no extra props like workerOptions are needed at this stage.

Regarding the Safari issue: transferControlToOffscreen (required for worker mode) is supported starting with Safari 16.4. could you confirm the exact version ? If it’s below 16.4, that would explain the error. If you're seeing this on 16.4 or newer, we'd definitely like to investigate further.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/transferControlToOffscreen#browser_compatibility

We’ll also look into the intermittent issues you've noticed in Firefox under memory pressure to see if any improvements can be made

theashraf avatar May 23 '25 04:05 theashraf

Hey @theashraf! Thanks a lot for the quick reply!

First.

It's great dotlottie-react supports the worker too! 💯 I gave it a try and it worked well, almost no CPU used as expected (just replaced DotLottieReact with DotLottieWorkerReact), however whenever the page re-renders due to navigation a different console error shows up for both crhome and firefox

Crhome: Latest Version 137.0.7151.41

1. Uncaught InvalidStateError Failed to execute transferControlToOffscreen.txt

Specific file in chrome dev tools Image

[!TIP] I believe what I am experiencing is related with this other issue according to it's description: https://github.com/LottieFiles/dotlottie-web/issues/326#issuecomment-2747054507

The error doesn't break the animation rendered, but the console errors keep appearing on navigation. This is my dotLottieWorkerReact component setup, nothing fancy:

...
return (
  <DotLottieWorkerReact
      workerId={workerId}
      src={`${window.location.origin}${genericGears}`}
      className={className}
      onMouseEnter={onMouseEnter}
      speed={1}
      loop={false}
      autoplay={true}
      dotLottieRefCallback={dotLottieRefCallback}
    />
)

Firefox Latest Version 138.0.4 (64-bit)

I tested on firefox too and was able to replicate the errors i saw before. These are the console errors:

  1. 1. Uncaught in promise DOMException.txt
  2. 2. memory allocation of 955328832 bytes failed.txt
  3. 3. Aborted.txt
  4. 4. Failed to load animation data from URL.txt

It seems firefox doesn't load the source well, but i am not sure.

[!NOTE] I hope the .txt files from both browsers help you debug better!

Second.

I double checked my SAFARI test environment and the version I am using is less than 16.4. I will see if i can upgrade to the latest version. 👍

sevilladiego8 avatar May 24 '25 16:05 sevilladiego8

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs.

github-actions[bot] avatar Jul 24 '25 02:07 github-actions[bot]

I also have that problem, but for me using DotLottieReact turned out to be the solution to "transferControlToOffscreen is not a function" error. Simpliest example bellow is what i used (DotLottieReact for suppot safari < 16.4). It works fine.

` import React from 'react'; import { DotLottieWorkerReact, DotLottieReact } from '@lottiefiles/dotlottie-react'; import { DotLottieProps } from './types/types.ts';

export const DotLottie = ({ animationData }: DotLottieProps) => { const [dotLottie, setDotLottie] = React.useState(null);

const dotLottieRefCallback = (dotLottie) => { setDotLottie(dotLottie); };

const canvas = document.createElement('canvas'); const DotLottieComponent = !canvas.transferControlToOffscreen ? DotLottieReact : DotLottieWorkerReact;

return <DotLottieComponent data={animationData} loop autoplay dotLottieRefCallback={dotLottieRefCallback} />; }; `

In turn, using DotLottie from "@lottiefiles/dotlottie-web" caused "transferControlToOffscreen is not a function" error. The solution described here partially helped. However, in my case, when changing animationData, the error starts falling again...

NickSemenov avatar Jul 31 '25 06:07 NickSemenov

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs.

github-actions[bot] avatar Oct 01 '25 02:10 github-actions[bot]