Vue.js和Node.js教程:托管在Azure静态Web Apps中的实时协作应用

633 阅读13分钟

实时协作

Vue.js and Node.js tutorial: a realtime collaboration app hosted in Azure Static Web Apps

这篇文章描述了我是如何建立一个实时协作应用,让Scrum团队可以用于规划扑克。规划扑克,也被称为Scrum扑克,是一种游戏化的技术,用于估计用户故事的大小。这有助于决定在一个冲刺阶段可以放多少个故事。通常使用斐波那契尺度的故事点作为衡量标准,但也有使用T-shirt尺寸的,如小、中、大。

我曾在许多不同的开发团队中工作,这些团队使用规划扑克。每个团队都有自己的解决方案,在我们都在家工作的情况下在线进行。这些解决方案从聊天信息、项目管理工具的插件到专门的网络应用程序都有。对我来说,聊天信息选项是最不可取的,因为一旦第一个团队成员提交了他们的投票,就太容易产生偏见了。**要想有一个好的规划扑克会议,重要的是要能在不被他人影响的情况下进行投票。**如今,实时协作工具是必不可少的,我喜欢使用那些使协作变得简单和直观的工具。

入职培训 @ Ably

这个项目是我在Ably的入职培训的一部分,我最近在那里开始担任高级开发人员倡导者。我被要求用Ably、Azure和一个JavaScript前端框架建立一些东西,以学习Ably Realtime SDK。我想做一些有趣但又实用的东西,这时我想到了Agile Flush,一个在线计划扑克应用。这主要是作为一个学习练习。但它有一个有用的最终结果,可以在这里使用:https://agileflush.ably.dev。源代码可以在GitHub上找到,我还录制了一个关于这个项目的YouTube视频,你可以在这里观看

敏捷的同花顺

最好的产品是那些使用起来摩擦力非常小的产品。对于Agile Flush来说,这意味着不需要注册和登录,也不要求用户提供关于他们自己或计划会议的任何信息。我们的想法是,团队成员在他们选择的通信工具中加入定期的在线规划电话,此外还可以访问Agile Flush网站,并能够立即开始投票。

Vue.js and Node.js tutorial: a realtime collaboration app hosted in Azure Static Web Apps

图1.敏捷同花顺应用程序

就功能而言,这个应用程序是非常基本的。

  • 可以开始一个新的会议。
  • 可以选择和取消选择一张卡片。
  • 投票的可见性可以切换为开/关。
  • 投票可以被重置。

图2中的流程图显示了这些步骤和条件。

Vue.js and Node.js tutorial: a realtime collaboration app hosted in Azure Static Web Apps

图2.Agile Flush功能

除了开始一个新的会话外,所有的操作都将在会话的所有参与者中同步数据。_显示/隐藏投票_和_重设投票_的动作将对其他参与者触发同样的功能。选择一张牌将为其他参与者增加(最初隐藏的)牌数,但选择的牌只对执行该动作的参与者可见。

技术栈。Vue.js、Node.js、Ably和Azure静态Web应用

Vue.js and Node.js tutorial: a realtime collaboration app hosted in Azure Static Web Apps

图3.敏捷同花顺的主要技术组件

Agile Flush是由Vue.js作为前端框架,Node.js Azure函数与Ably进行认证,Ably作为实时消息传递组件,以及Azure静态Web Apps来承载Vue.js应用程序和Node函数。

Vue.js应用程序

前端使用Vue.js v3构建。此外,它还使用Vue Router和Vuex。Vue.js应用程序由以下组件组成。

  • HomePage.vue;应用程序的主要布局。
  • SessionSection.vue,投票环节开始后显示的布局。
  • CardItem.vue;这个组件用于Vuex商店_卡片_集合中的每个投票卡。
  • FooterSection;一个显示社会链接的段落。

图4显示了这些组件的位置。_构建应用程序_部分提供了对这些组件的详细描述。

Vue.js and Node.js tutorial: a realtime collaboration app hosted in Azure Static Web Apps

图4.Vue组件的布局

Node.js功能

Vue.js应用程序需要与Ably安全通信。在创建一个新的Ably Realtime实例时,需要一个认证令牌,但这个令牌不应该在前端硬编码,因为它可能被其他人读取和滥用。相反,认证令牌是通过_createTokenRequest_函数向Ably请求的,该函数是用Node.js编写的,在后端作为Azure函数运行。该函数使用Ably的API密钥,该密钥从应用程序设置中获取,没有人可以看到。该函数创建了一个Ably实时客户端的实例,该实例被用来从Ably获得一个新的认证令牌。当Vue.js应用程序创建一个新的Ably Realtime实例时,Node.js Azure函数的URL被提供在_authUrl_参数中,以便安全地获得令牌。

使用Ably的Pub/Sub

Agile Flush是一个实时协作工具。每个参与者在他们的客户端应用程序上提交他们的投票(或撤销他们的投票),所有这些行动都实时同步到其他参与者的应用程序上,因此每个人都可以看到相同的结果并进行讨论。一个pub/sub(发布/订阅)机制是这种类型的通信的理想选择。Ably是一个实时的消息传递平台,可以大规模地进行pub/sub。在这种情况下,每个客户端应用程序既是发布者也是订阅者。一个客户端触发了向特定的Ably通道(与会话绑定)发布投票,所有客户端都订阅了这个通道并处理传入的投票信息。每个客户端都有自己的Vuex存储,这个存储的状态由Ably广播给订阅者的消息来保持同步。

Azure静态Web应用

Vue应用程序和Node功能需要被托管在某个地方。我选择了Azure Static Web Apps,因为我对Azure平台非常熟悉,而且Static Web Apps对于需要Azure Functions形式的一些后端功能的网站来说是个不错的选择。当Azure静态Web应用服务被创建时,它需要连接到代码所在的GitHub仓库。在创建过程中,会自动创建一个GitHub工作流并添加到仓库中。这个工作流程包括构建和部署应用程序和Azure功能到Azure云的步骤。

构建应用程序

在本节中,我将介绍我构建Agile Flush的步骤。我将提供足够的说明,让你能够跟随并从模板库中创建应用程序。然而,如果你想立即看到(并运行)最终的解决方案,请看一下GitHub仓库,并按照README中的说明操作。

使用GitHub模板库

Azure Static Web Apps是一个很好的服务,可以托管静态网站和功能。我与Azure合作多年,所以我对它最熟悉。Azure文档中确实包含了几个关于使用Azure Static Web Apps与几个流行的前端框架的快速入门,但我发现他们的Vue.js例子有点过时了。我创建了一个新的GitHub repo模板,staticwebapp-vue-vite, 可以在这里找到。

这个_staticwebapp-vue-vite_模板包含了一个完全工作的Azure静态Web应用,它已经预先配置好了。

  • Vue.js v3;一个知名的渐进式JavaScript框架。
  • Vue Router v4;Vue的一个路由插件。
  • Vuex v4;一个状态管理模式和库。由我的同事Srushtika推荐。
  • Node.js API;一个基于普通JavaScript的Azure函数。
  • Vite.js;一个快速的JavaScript构建工具。我的同事Jo推荐的,他在我们迄今为止最大的项目中一直使用这个工具。FFS聊天应用

我建议使用该模板为静态Web App创建自己的GitHub仓库,以避免编写模板代码。

我还建议使用VS Code作为编辑器,因为有几个扩展可以直接在VS Code中使用Azure静态Web应用和Azure函数。当你使用模板库,用VS Code打开文件夹时,会要求你安装这些扩展。

文件夹结构

staticwebapp-vue-vite 模板包含以下文件夹。

  • api;包含基于vanilla JavaScript Azure Function的Node.js API。
  • public;用于静态文件,如favicon.ico。
  • src;包含Vue.js v3应用程序。这包括这些子文件夹。
  • components;用于单个.vue组件。
  • router;用于 VueRouter 配置。
  • store;用于Vuex配置。

为了安装Vue.js应用程序和Node.js函数的依赖项,在根目录下运行这个程序。

npm run init

现在我们已经有了基本的配置,让我们开始更新Node.js函数。

更新Node.js函数

Node.js函数需要与Ably通信,以检索认证令牌。Ably JavaScript客户端库将被用于此。

  • 在_api_ 文件夹中,运行。
npm install ably

这将安装Ably客户端库,以便与Node函数一起使用。

  • 将文件夹从_getTitleFromApi_重命名为_createTokenRequest_,这样函数的目的就清楚了。
  • 现在Ably库已经可用,HTTP函数可以被更新以使用Ably实时客户端。用下面的实现替换_createTokenRequest_/_index.js_中的现有代码。
const Ably = require('ably/promises');
 
module.exports = async function (context) {
    const id = `id- + ${Math.random().toString(36).substr(2, 16)}`;
    const client = new Ably.Realtime(process.env.ABLY_API_KEY);
    const tokenRequestData = await client.auth.createTokenRequest({ clientId: id });
    context.res = {
        headers: { "content-type": "application/json" },
        body: JSON.stringify(tokenRequestData)
    };
};

注意,在创建Ably.Realtime客户端的新实例时,会使用一个环境变量_ABLY_API_KEY_。我们还没有指定任何API密钥,所以让我们先做这个。

创建Ably应用程序并使用API密钥

Node.js Azure函数要连接到Ably,需要一个API密钥来完成。如果你还没有Ably账户,请注册一个。

  • 如果你有一个账户,请登录ably.com,然后创建一个新的应用程序并复制API密钥
  • API密钥应该放在位于版本库_api_ 文件夹下的_local.settings.json_文件中。由于该文件是.gitignored的,你需要自己创建该文件并添加以下内容。
{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "",
        "FUNCTIONS_WORKER_RUNTIME": "node",
        "ABLY_API_KEY": "YOUR_API_KEY"
    }
}
  • 将_YOUR_API_KEY_替换为实际的Ably API密钥。

这个_local.settings.json_文件只在你的本地机器上使用,不应该被检入git,因为它通常包含要保密的密钥。一旦应用程序准备好被部署,就需要将Ably API密钥添加到Azure静态Web App资源的应用程序设置中。这将在本帖的 "部署到Azure静态Web应用 "部分介绍。

创建Vue.js组件

本节列出了对模板库中已存在的Vue文件的修改和添加。

1.1.App.vue
位于src文件夹中的App.vue组件是应用程序的根组件。目前,它只包含一个导入的HomePage.vue组件。

这个实现替换App.vue的内容。

这个文件中的_模板_部分仍然是一样的,使用HomePage组件。_脚本_部分现在包含来自Vuex商店的getters和动作,在本帖的Vuex商店部分显示。_样式_部分包含关于字体和颜色的css,适用于整个应用程序。

2.HomePage.vue
位于_src/components_文件夹中的_HomePage.vue_组件包含主页的模板。

这个实现替换文件的内容。

这个组件导入了_SessionSection_和_FooterSection_组件。_脚本_部分包含_启动_方法,通过分别调用Vuex动作_startSession_和_instantiateAblyConnection_来启动一个新的投票会话和与Ably的新连接。此外,该组件还包含了切换投票结果可见性的按钮,以及使用Vuex商店的_toggleShowResults_和_resetVoting_动作来重置投票结果。

3.SessionSection.vue
在_src/components_文件夹中创建一个名为_SessionSection.vue_的新文件。这个组件将包含一个会话开始后的布局和行为的模板。

这个实现替换文件的内容。

这是一个非常小的组件,它只使用这两个getters从Vuex商店检索数据:getNrOfParticipantsVoted_和_getNrOfParticipantsJoined

4.4.CardItem.vue
在_src/components_文件夹中创建一个名为_CardItem.vue_的新文件。这个组件将包含一张投票卡的模板。这个组件将被用于Vuex商店中_卡片_集合中的所有卡片。

这个实现替换文件的内容。

脚本部分包含_selectCard_方法,用于选择和取消选择卡片。这个方法调用Vuex商店中的_doVote_或_undoVote_动作。

5.FooterSection.vue
在_src/components_文件夹中创建一个名为_FooterSection.vue_的新文件。这个组件将包含页面页脚的模板。它将显示作为静态信息存在的社会链接。

这个实现替换文件的内容。

6.Vuex商店
存储器是Vue应用程序的核心,因为它管理着应用程序的状态,并将通过Aby通道处理连接的客户端之间的状态同步。 Vuex存储的主要实现位于_src/store/index.js_。

这个实现替换该文件的内容。

在_src/store_的位置上添加两个额外的文件。

  • cardModule.js; cardModule将处理投票卡的状态。用这个实现替换该文件的内容。
  • _realtimeModule._js; realtimeModule将处理任何与Aply Realtime有关的状态。用这个实现来替换文件的内容。

realtimeModule使用Able Realtime客户端来与Ably进行通信。要安装客户端库,在存储库的根目录下运行这个。

npm install ably

Vuex存储包含以下部分。

  • state;一个描述状态的属性集合。例如,cardModule中的_card_属性,包含所有投票卡的定义。
cards: [
    {
        number: '0',
        count: [],
        style: 'card0',
    },
    {
        number: '0.5',
        count: [],
        style: 'card05',
     },
     ...
  • getters;一个查询状态的方法集合。例如,_voteCountForCard_获取器,检索指定卡号的投票数。
voteCountForCard: (state) => (cardNumber) => 
    state.cards.filter((card) => card.number === cardNumber)[0].count.length
  • 突变;一个改变状态属性的方法集合。例如,_addParticipantVoted_突变,将客户投票添加到_卡片_状态中。
addParticipantVoted(state, clientVote) {
    const index = this.getters.cardIndex(clientVote.cardNumber);
    if (!state.cards[index].count.includes(clientVote.clientId)) {
        state.cards[index].count.push(clientVote.clientId);
    }
}
  • 行动;一组方法,结合突变和Ably API来管理和同步客户端的状态。例如,_doVote_动作调用_addParticipantVoted_突变和_publishVoteToAbly_动作。
doVote({ dispatch, commit, getters }, cardNumber) {
    const clientVote = {
        clientId: getters.clientId,
        cardNumber,
    };
    commit('addParticipantVoted', clientVote);
    dispatch('publishVoteToAbly', clientVote);
}

_store/index.js_中的_startSession_动作依赖于_generateSessionId_方法,该方法目前还不可用。

  • 在_src_文件夹内创建一个名为_util_的新文件夹。
  • 在这里创建一个新文件,命名为_sessionIdGenerator.js_。
  • 这个实现替换该文件的内容。

_generateSessionId_方法被用来创建一个基于两个形容词和一个名词的随机会话ID。这个ID被放在应用程序的查询字符串中,所以它可以很容易地与其他参与者分享。

关于组件如何与Vuex存储互动的更多信息,请看GitHub仓库中的序列图。

现在一切准备就绪,你可以在本地通过运行来启动该应用程序。

npm run all

将实时协作应用部署到Azure静态Web应用中

通过Azure门户或Azure CLI,可以将应用部署到Azure静态Web应用中。

在这两种情况下,由于你使用的是_staticwebapp-vue-vite_ GitHub仓库模板,所以你可以跳过创建仓库的步骤。

对于从头开始创建Azure静态Web应用或从VSCode管理现有应用,我强烈建议使用VS Code的Azure静态Web应用扩展。当你使用_staticwebapp-vue-vite_模板库时,这个扩展应该是推荐安装的。

总结

实时协作工具在日常工作中变得越来越重要。幸运的是,由于Vue.js这样的模块化前端框架、Ably这样的实时pub/sub服务以及大量的各种云服务,创建实时体验对开发者来说越来越容易。

Agile Flush是开源的,你可以在GitHub仓库中查看。你可以自由地分叉它,并扩展它,使其成为你自己的(更新卡片以使用T-shirt大小的人?)README解释了如何在本地或GitHub Codespaces中构建和运行它。我还添加了CodeTours,解释了软件库中所有重要的部分。如果你打算分叉Agile Flush并只用于你的团队,你可以使用Azure Static Web Apps的免费层,以及Ably的免费层,这样你就可以零成本地托管和运行这个应用了。