1

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! :)

4
  • Sorry I forgot to mention I tried axios also to get the json when the component mounts, but I received the same error message mentioned above. @EmielZuurbier Commented Feb 10, 2020 at 10:53
  • Regarding your update: How exactly do you use your component in the template ? Commented Feb 10, 2020 at 14:19
  • It's ok, I figured out where I was going wrong, updated my question again - thanks a lot for your help! Commented Feb 10, 2020 at 14:29
  • How do you resolve the dynamic import issue? i can not seems to dynamic import the lottie .json files. it does not display the animation without any error... Commented Apr 24, 2020 at 11:32

2 Answers 2

5

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the very informative response, I'll take a look at repurposing my project to use lottie-web instead of any wrapper packages. I have updated my question with your feedback, but I'm getting an error and not sure where I'm going wrong. This is my first time lazy loading a component :)
0

When the animationData property is set it is a function, hence the line:

Expected Object, got Function

It needs an object, not a function.
The function being:

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

When defining the animationData property you need to set an object as its value. Then when mounting fetch the data (or use Axios if you prefer that) to update the animationData property on the component.

N.B. I have never used Vue, so I hope that what I am saying is correct.

export default {
    name: 'animation',
    components: {
        vueLottie
    },
    data () {
        return {
           speed: 1,
           animationData: {}
        }
    },
    computed: {
        lottie () {
            return this.$refs.lottie
        }
    },
    mounted() {
        fetch('/users/username/documents/projectname/public/data/filename.json')
            .then(response => response.json())
            .then(json => this.animationData = json;);
        )
    }
}

1 Comment

Unfortunately this will not work as vue-lottie will call lottie.loadAnimation with empty object before the download is completed...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.