Hot questions for Using Lottie in lazy loading

Top 10 Java Open Source / Lottie / lazy loading

Question:

I am using Vue.js and Laravel for my project and recently added two animations using a plugin named Lottie. Each animation is a component, and they both use an individual JSON file to animate a group of PNG images (similar to a PNG sequence). These two JSON files are stored locally in the project folder under the path /public/data/.

Firstly the JSON files are not being read unless I put in the absolute path (/users/username/documents/projectname/public/data/filename.json), is there no way I can get this to work just by using /data/filename.json?

Secondly, when I add the code below in my component, my JS files are compiled to separate chunks as expected:

const animationData = () =>
  import("/users/username/documents/projectname/public/data/filename.json");

I get the following error when the animation tries to run:

Invalid prop: type check failed for prop "data". Expected Object, got Function 

found in

---> <VueLottie>

However when I import my json file using a normal import in my component like below it works fine and shows the animation:

import animationData from "/users/username/documents/projectname/public/data/filename.json";

My animation components are both set up like this:

<template>
        <vue-lottie ref="lottie" loop autoplay :data="animationData" :height="400" :width="400"></vue-lottie>
</template>

<script>
    import vueLottie from "vue-lottie-ssr";
    import animationData from '/users/username/documents/projectname/public/data/filename.json'

    export default {
        name: 'animation',
        components: {
            vueLottie
        },
        data () {
            return {
                speed: 1,
                animationData
            }
        },
        computed: {
            lottie () {
                return this.$refs.lottie
            }
        }

    }
</script>

I have also tried getting the JSON file via an axios call when the component mounts, but the same error occurs.

Update

I updated my code so that each component is lazy loaded instead of the JSON file. Like so:

components: {
  WinAnimation: () => import("./WinAnimation.vue");

  LoseAnimation: () => import("./LoseAnimation.vue");
}

However now I'm getting the following error:

Unknown custom element: <win-animation> - did you register the component correctly? For recursive components, make sure to provide the "name" option.

Update 2

I realised why I was getting an error message. The correct way was to add the following at the top of my script inside the parent vue file.

const winAnimation = () => import("./WinAnimation.vue");
const loseAnimation = () => import("./LoseAnimation.vue");

and then inside export default {...} I forgot to add the names, so:

components: { winAnimation, loseAnimation }

Now my code has been split and my app.js file size has reduced by almost a half! :)


Answer:

1st - don't use vue-lottie library. If you take a look at the source code, the main and only thing which should be provided by this library is component src/lottie.vue (+ it's dependency lottie-web) but for some reason, NPM package also contains whole demo app including the demo JSON file (src/assets/pinjump.json)

If you take a look at lottie.vue component, its just very little and very simple wrapper for lottie-web which provides main functionality. By getting rid of vue-lottie you will get following benefits:

  1. vue-lottie completely ignores one of the lottie-web options which is using path instead of animationData - documentation is not very clear here but I would guess that by providing path, the library will try download the animation data ad-hoc so you don't need to include it in your bundle. Worth trying imho...

  2. Loading animation data on demand

    • why are you using dynamic import on JSON file instead of dynamically importing whole component ? By making separate chunk on component level, dynamic chunk will include not only your json data but also lottie-web which is also not small. And Vue will handle loading of the component without any additional code changes...
    • if you still want to load on demand only your JSON data, you must understand that Webpack dynamic import (import(".....")) is returning Promise and lottie-web (and in turn vue-lottie) is expecting object. So you must do something like this:
<script>
    import lottie from 'lottie-web';

    const animationData = () =>
       import("/users/username/documents/projectname/public/data/filename.json");

    export default {
      mounted () {
        animationData().then(function(data) {
          this.anim = lottie.loadAnimation({
            // other options 
            animationData: data
          })
        });
      }
    }
</script>

Update

You should be always very careful when considering adding 3rd party components into your project. One more thing I'v noticed is that lottie-web has destroy() method in it's API. This indicates that it is creating some resources (DOM elements probably) which needs to be cleaned up. This is something vue-lottie component is not handling at all and can lead to nasty memory leaks in your app. You can read about the problem here

Question:

I want to implement lazy loading in my React app but most of the files are JSON. Few of them are loading when the viewport width is less than e.g. 768px and I don't want to load them in the Desktop app when they are not needed. Is there any way to load the JSON file with React.lazy()?

My JSON file is generated with Adobe After Effect extensions called: 'Bodymovin' and later I am importing this file like this:

import * as background from './background.json';
import * as backgroundLarge from './background-large.json';
import * as backgroundMedium from './background-medium.json';
import * as backgroundMobile from './background-mobile.json';
import * as backgroundSmallMobile from './background-smallMobile.json';
import * as tree from './tree.json';
import * as treeLarge from './tree-large.json';
import * as treeMedium from './tree-medium.json';
import * as treeMobile from './tree-mobile.json';
import * as treeSmallMobile from './tree-smallMobile.json';

I was trying to load it normally like any other components with default export but it's not working.

const treeMedium = lazy(() => import('./tree-medium.json'));

When I import JSON normally I am using it later like this:

backgroundOptions: {
      loop: true,
      autoplay: true,
      animationData: background.default,
    },

And pass this object into Lottie component from react-lottie

Can I convert it to lazy loading or I am thinking wrong?


Answer:

It is not React component, so you shouldn't wrap it to the lazy call. Basically you just need to load it and handle a promise. Something like:

componentDidMount() {
 import('./tree-medium.json').then(background => {
  this.setState({background})
 })
}

and then use it somewhere in your render