在介绍VPA整体的运行流程之前,我们先来简单的了解一下VPA内包含的组件,这有利于更好的理解项目的运行机制。
在对项目的理解逐渐加深之后,可以在之后的章节详细了解不同的组件。
在整个 VPA 设计过程中,组件大体可以分为两种类型:
系统组件就是 VPA 的内置组件,它们实现了 VPA 的最基础的能力,也是解决标准 VPA 的最小化组件集合。
下图,是 VPA 在运行过程中的 redux 数据结构。可以看到每一个会话卡片都是一个组件,在图片中,使用红色的框线标记了出来。包括开始屏幕上的欢迎语、快捷关键字、用户发送的消息、系统回复的消息等。
VPA 在标准流程中,是有一些内置功能的。例如:发起会议、日程的输入交互、天气查询功能、找人打电话和发短信、打开应用和简单的文字回答等能力。这些能力都是通过系统组件来实现的。
这些功能一般组件开发者不需要过分关心,但是系统组件处理组件的数据和开发模式和自定义组件是非常类似的,所以开发者可以参考系统组件的实现,来开发自己的组件。
系统组件和自定义组件在加载流程上有些区别,下面将详细介绍这两种组件的加载流程。
当我们调用 vpa.sendMessage
方法时,VPA 的 redux 数据中,将增加一个系统组件到消息列表中,名称叫做 ISay
来处理这个消息。(位置在
src/card/ISay
目录下)
这个组件处理了用户的输入,将用户的输入内容使用 xiaoyouLight.requestChat
发送给后端,然后等待后端的回复。
当后端返回数据的时候, 此时可以观察 network 的响应数据,其中有一个字段是 responses
,这个字段是一个数组,里面包含了后端返回的所有的响应数据。
🍉 ` 此处内容可以定制,以便于在 daily 环境不稳定的情况下,或者是需要快速模拟特别响应数据的情况下,可以直接修改响应数据。
处理该数组的过程,仍然是 ISay
这个组件。组件将会使用 Array.prototype.forEach
方法,遍历这个数组,将其响应添加到消息列表的
redux 中。
这个过程是最复杂,也是组件加载的核心:
在前面的一步中,消息列表的数据会渲染在主屏幕中。每一个消息,将视作为一个卡片。而卡片的最外边,是一个卡片容器,叫做
CardWrapper
。(位置在 src/card/CardWrapper.ts
中)
这个容器是一个组件,它的作用是根据响应的数据模型,以及不同的加载策略,来加载不同的组件。
在 CardWrapper
的加载生命周期里,有一个 loadCard
函数,它的流程大致如下:
判断依据是响应数据中的 res.data.vpaUIResourceID
。
根据 process.env.NODE_ENV === 'development'
来判断是否处于开发模式下。如果是开发模式下,会有更多开发的环节嵌入。
在自定义响应中,与 vpaUIResourceID
同级下,可以配置一个 useLocalDevCard
字段,该字段的值可以填写该资源需要加载的本地开发组件的路径,例如 @remote/XX
。(以 @remote 开头,相对于
src 目录)
目的是绕过资源管理平台,直接加载本地的开发组件。
此时,加载标记记作:Step 1.11
如果没有找到映射,则会从资源管理平台加载远程组件。将最大程度模拟生产环境下的加载流程。
加载的时候,会有一系列的动作,用于对比版本、下载资源、加载资源等等。不过细节对于组件开发者来说,不需要过多关心。
此时,加载标记记作:Step 1.12
如果不是在开发模式下,也就意味着当前环境是在生产环境下,将会按照资源 id,从资源管理平台加载远程组件。 在这个过程中,还有一系列动作,用于对比版本、下载资源、加载资源等等。不过细节对于组件开发者来说,不需要过多关心。
此时,加载标记记作:Step 1.2
则按照 src/card/map.ts
中的组件映射表,来加载对应的系统组件。
此时,加载标记记作:Step 2
在开发组件的过程中,需要对这个流程有一个基本的了解,尤其是重点关注加载标记的Step
,可以快速调试和定位问题。