【问题标题】:How can I correctly lazy load a json file in Vue.js to reduce bundle size?如何正确延迟加载 Vue.js 中的 json 文件以减小包大小?
【发布时间】:2020-05-25 15:49:23
【问题描述】:

我在我的项目中使用 Vue.js 和 Laravel,最近使用名为 Lottie 的插件添加了两个动画。每个动画都是一个组件,它们都使用单独的 JSON 文件来为一组 PNG 图像制作动画(类似于 PNG 序列)。这两个 JSON 文件本地存储在 /public/data/ 路径下的项目文件夹中。

首先,除非我输入绝对路径 (/users/username/documents/projectname/public/data/filename.json),否则不会读取 JSON 文件,我有没有办法只需使用 /data/filename.json 就可以让它工作?

其次,当我在我的组件中添加以下代码时,我的 JS 文件会按预期编译为单独的块:

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

动画尝试运行时出现以下错误:

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

found in

---> <VueLottie>

但是,当我在我的组件中使用正常导入导入我的 json 文件时,它可以正常工作并显示动画:

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

我的动画组件都是这样设置的:

<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>

我也尝试过在组件挂载时通过 axios 调用获取 JSON 文件,但出现同样的错误。

更新

我更新了我的代码,以便每个组件都是延迟加载的,而不是 JSON 文件。像这样:

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

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

但是现在我收到以下错误:

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

更新 2

我意识到我收到错误消息的原因。正确的方法是在父 vue 文件中的脚本顶部添加以下内容。

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

然后在 export default {...} 里面我忘了添加名字,所以:

components: { winAnimation, loseAnimation }

现在我的代码已经被拆分,我的 app.js 文件大小减少了近一半! :)

【问题讨论】:

  • 对不起,我忘了提到我尝试 axios 在组件挂载时获取 json,但我收到了上面提到的相同错误消息。 @EmielZuurbier
  • 关于您的更新:您在模板中究竟是如何使用组件的?
  • 没关系,我知道哪里出错了,再次更新我的问题 - 非常感谢您的帮助!
  • 如何解决动态导入问题?我似乎无法动态导入 lottie .json 文件。它不会显示没有任何错误的动画...

标签: javascript json vue.js lazy-loading lottie


【解决方案1】:

当animationData 属性被设置时,它是一个函数,因此行:

预期对象,得到函数

它需要一个对象,而不是一个函数。
功能是:

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

定义animationData 属性时,您需要将对象设置为其值。然后在挂载fetch 数据时(如果您愿意,也可以使用Axios)来更新组件上的animationData 属性。

注意我从来没有使用过 Vue,所以我希望我所说的是正确的。

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;);
        )
    }
}

【讨论】:

  • 不幸的是,这不起作用,因为vue-lottie 将在下载完成之前使用空对象调用lottie.loadAnimation...
【解决方案2】:

第一个 - 不要使用 vue-lottie 库。如果你看一下源代码,这个库应该提供的主要和唯一的东西是组件src/lottie.vue(+它的依赖关系lottie-web)但是出于某种原因,NPM 包还包含整个演示应用程序 包括演示 JSON 文件 (src/assets/pinjump.json)

如果您查看lottie.vue 组件,它只是提供主要功能的lottie-web 的非常小且非常简单的包装器。通过摆脱vue-lottie,您将获得以下好处:

  1. vue-lottie 完全忽略了使用lottie-web 的lottie-web 选项之一——这里的文档不是很清楚,但我猜想通过提供path,库将尝试下载动画数据ad-hoc 所以你不需要将它包含在你的包中。值得一试恕我直言...

  2. 按需加载动画数据

    • 为什么你对 JSON 文件使用动态导入而不是动态导入整个组件?通过在组件级别制作单独的块,动态块将不仅包括您的 json 数据,还包括lottie-web,这也不小。并且 Vue 将处理组件的加载,而无需任何额外的代码更改...
    • 如果你仍然想只按需加载你的 JSON 数据,你必须明白 Webpack 动态导入 (import(".....")) 正在返回 Promise,而 lottie-web (反过来 vue-lottie) 正在等待对象。所以你必须这样做:
<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>

更新

在考虑将第 3 方组件添加到您的项目时,您应该始终非常小心。我注意到的另一件事是 lottie-web 在其 API 中有 destroy() 方法。这表明它正在创建一些需要清理的资源(可能是 DOM 元素)。这是vue-lottie 组件根本没有处理的事情,可能会导致您的应用程序中出现严重的内存泄漏。您可以阅读有关问题here

【讨论】:

  • 感谢您提供非常丰富的回复,我将看看重新调整我的项目以使用 lottie-web 而不是任何包装器包。我已根据您的反馈更新了我的问题,但我遇到了一个错误,不知道哪里出错了。这是我第一次延迟加载组件:)
猜你喜欢
  • 2019-05-01
  • 2020-01-18
  • 1970-01-01
  • 1970-01-01
  • 2020-09-24
  • 1970-01-01
  • 1970-01-01
  • 2018-04-28
  • 1970-01-01
相关资源
最近更新 更多