LottieFiles / dotlottie-web

Official LottieFiles player for rendering Lottie and dotLottie animations in the web. Supports React, Vue, Svelte, SolidJS and Web Components.
https://developers.lottiefiles.com/docs/dotlottie-player/
MIT License
159 stars 11 forks source link

"Dotlottie works fine on localhost but not in production" - content type detection causes animation not to load. #282

Closed invernizzi closed 2 months ago

invernizzi commented 3 months ago

Hello there!

I want to share a DotLottie quirk, in the hope it can save someone else time.

Specifically: DotLottie decides how to load a particular animation (in the lottie or dotlottie format) based on the content type of the URL containing the animation data.

These are the lines making that decision.

      if (['application/json', 'text/plain'].some((type) => contentType.startsWith(type))) {
        data = await response.text();
      } else {
        data = await response.arrayBuffer();
      }

This behavior causes a tricky lite quirk with Vite.

In development mode, files imported like so are served with an empty content type. That causes dotlottie to work correctly if that file is a dotlottie one (arrayBuffer() is called).

import walkAnimationDataUrl from "@/public/walk.lottie?url";

However! In production, the same line is served with a content type of text/html. Dotlottie will load it as text (text() is called), but it won't raise any error (at least, with my file). Instead, it will cause the browser process to hang after a few seconds.

DotLottie devs: perhaps you could let users specify the file format as an option instead of this. Since I'm using Vite with pretty much default options, I wonder if I'm the first to face this issue.

(I need a celebratory beer after solving this one)

theashraf commented 3 months ago

@invernizzi Thank you so much for taking the time and effort to investigate and share this issue in such detail.

However, I believe this is not correct. If the content-type of the file is text/html, DotLottie will still attempt to load the file as a .lottie array buffer.

According to this line, if the content-type is text/html, we would hit the else statement:

if (['application/json', 'text/plain'].some((type) => contentType.startsWith(type))) {
  data = await response.text();
} else {
  data = await response.arrayBuffer();
}

So, according to your scenario, it should be loaded as a .lottie file in both development and production environments, right ?

Probably the walkAnimationDataUrl in production doesn't resolve to a valid .lottie file ? šŸ‘€

invernizzi commented 3 months ago

Thanks for the quick response!

your reasoning makes sense, but that's a dotlottie file, not a lottie one. I'm not sure why the use the same extension by convension (as opposed to .dotlottie), but that's the convention followed by the site describing the file format.

I've created a simple reproduction of this bug in this repo, using an example animation from that same site. Here it is: https://github.com/invernizzi/dotlottie-web-bug-282

theashraf commented 3 months ago

@invernizzi thanks for reproducing the issue. It seems that Vite can't recognize the .lottie file type and add the proper content-type header accordingly.

On preview: image

On dev: image

In my opinion, one way we can improve this from the dotlottie-web side is to resolve all src's as arrayBuffers and check for the ZIP magic number. Given the fact that .lottie is just a ZIP archive, we can use the signature of a ZIP file to identify it. I believe the ZIP signature in hex is: 50 4B 03 04

I feel that this is a good approach, as it is a common practice used to recognize file types. If this signature is not present, then it's a Lottie JSON file.

x5hwuk7nc6jsudcc commented 2 months ago

šŸ‘ great issue and solution - can we get this merged in to a release?

theashraf commented 2 months ago

@x5hwuk7nc6jsudcc I've raised the PR for review, and it will be merged soon

theashraf commented 2 months ago

has been released in dotlottie-web@v0.29.2