当前位置:   article > 正文

怎么构建有推送通知的 GitHub 跟踪器,你知道吗_github tracker

github tracker

在本文中,您将学习如何构建一个 GitHub 跟踪器,当跟踪的存储库中有新的问题/PR 时,它会通过发送推送通知来通知用户。

如果您选择加入,GitHub 已经通过电子邮件发送通知,但许多研究表明,推送通知比电子邮件更能吸引用户。按照本教程构建 GitHub 跟踪器后,您将学会如何:

  • 添加服务工作者并将跟踪器转换为PWA
  • 订阅推送通知
  • 使用GitHub API
  • 通过Vercel云函数发送推送事件
  • 使用EasyCron定期获取新问题

先决条件

阅读本文需要一些技能和服务:

  • 安装了Node.js和 npm
  • 先前的Svelte知识
  • 一个免费的GitHub帐户,因为我们使用的是GitHub API
  • 一个免费的MongoDB Atlas帐户,用于在云中使用 MongoDB
  • 用于部署应用程序和云功能的免费Vercel帐户

什么是推送通知?

让我们来看看这些所谓的“推送通知”是什么。

您必须熟悉定期通知。这些是出现在屏幕上的小气泡文本,用于通知您某些事情。推送通知类似,只是它们不是按需生成的,而是在接收推送事件时生成的。推送通知在应用程序关闭时起作用,而常规通知要求您打开应用程序。

现代 Web 浏览器(如 Chrome)通过使用称为服务工作者的东西支持推送通知。Service Worker 是独立于浏览器主线程运行的一小段 JavaScript,因此,如果您的应用程序安装为 PWA(渐进式 Web 应用程序),则可以离线运行。

推送通知用于聊天应用程序中以在用户有未读消息时通知用户,在游戏中,通知用户游戏事件,在新闻站点中,通知用户突发文章,以及用于许多其他目的。

在您的应用程序中显示推送通知有四个步骤:

  1. 请求许可window.Notification.requestPermission()
  2. 将您的应用程序转换为游戏 PWA 并安装它
  3. 订阅推送事件
  4. 收到推送事件后,发送通知

第 1 步:创建跟踪器

让我们在本文中使用 Svelte 和Vite.js,而不是 Rollup。顾名思义,Vite 比 Rollup 更快,并且还提供了对环境变量的内置支持。要使用 Svelte 和 Vite 创建新项目,请运行以下命令:

npm init vite

选择要成为的框架svelte。如果你愿意,你可以使用 TypeScript。我将使用常规的 JavaScript。

接下来,cd进入项目文件夹,您可以将TailwindCSS添加到您的应用程序并使用以下命令安装所有依赖项:

  1. npx svelte-add tailwindcss
  2. # Install packages
  3. yarn install # or npm install

最后,在您喜欢的代码编辑器中打开项目并在http://localhost:3000npm run dev上运行或yarn dev启动应用程序。

跟踪器将如何工作

我们将使用 GitHub API 获取用户跟踪的存储库的问题列表和拉取请求。用户跟踪的存储库及其用户名将存储在 MongoDB 数据库中。

第一步是提示用户输入他们的用户名。Create 
src/lib/UsernamePrompt.svelte,它将是执行此操作的组件。这是我的表单 UI,但您可以根据需要进行设计:

  1. <script>
  2. let username = "";
  3. async function submit() {
  4. // TODO
  5. }
  6. </script>
  7. <form
  8. on:submit|preventDefault="{submit}"
  9. class="mx-auto min-w-[350px] max-w-[1100px] w-[50%] border border-gray-500 rounded my-4 px-6 py-4"
  10. >
  11. <h1 class="text-center text-3xl m-4">Enter a username</h1>
  12. <p class="text-center text-xl m-4">Enter a username to use this tracker</p>
  13. <input
  14. type="text"
  15. class="rounded px-4 py-2 border border-gray-300 w-full outline-none"
  16. placeholder="Username"
  17. aria-label="Username"
  18. bind:value="{username}"
  19. />
  20. <button
  21. class="mt-4 border border-transparent bg-blue-500 text-white rounded px-4 py-2 w-full"
  22. >
  23. Submit
  24. </button>
  25. </form>

像这样添加这个组件App.svelte:

  1. <script>
  2. import UsernamePrompt from "./lib/UsernamePrompt.svelte";
  3. </script>
  4. <UsernamePrompt />

接下来,让我们添加主动跟踪器 UI。创建文件src/lib/Tracker.svelte并在其中添加以下代码:

  1. <script>
  2. let repo = "";
  3. function track() {
  4. // TODO
  5. }
  6. function untrack(repo) {
  7. // TODO
  8. }
  9. </script>
  10. <form
  11. on:submit|preventDefault={track}
  12. class="mx-auto min-w-[350px] max-w-[1100px] w-[50%] border border-gray-500 rounded my-4 px-6 py-4"
  13. >
  14. <h1 class="text-center text-3xl m-4">GitHub tracker</h1>
  15. <input
  16. type="text"
  17. class="rounded px-4 py-2 border border-gray-300 w-full outline-none"
  18. placeholder="Enter the repository's URL"
  19. aria-label="Repository URL"
  20. bind:value={repo}
  21. />
  22. <button
  23. class="mt-2 border border-transparent bg-blue-500 text-white rounded px-4 py-2 w-full"
  24. >Track repository</button
  25. >
  26. <h2 class="mt-4 text-2xl">Tracked repositories</h2>
  27. <ul class="m-2 list-decimal">
  28. <!-- We'll use a loop to automatically add repositories here later on. -->
  29. <li class="py-1 flex items-center justify-between">
  30. <a class="text-gray-500 hover:underline" href="https://github.com/test/test"
  31. >https://github.com/test/test</a
  32. >
  33. <button class="text-red-500 cursor-pointer" on:click={() => untrack("")}
  34. >Untrack</button
  35. >
  36. </li>
  37. </ul>
  38. </form>

要测试您的组件,请暂时将组件换成UsernamePrompt新Tracker组件App.svelte:

  1. <script>
  2. // import UsernamePrompt from "./lib/UsernamePrompt.svelte";
  3. import Tracker from "./lib/Tracker.svelte";
  4. </script>
  5. <!-- <UsernamePrompt /> -->
  6. <Tracker />

您的屏幕现在应该如下所示:

注意:记得恢复App.svelte到之前的代码!

第 2 步:设置云功能

我们需要有一个后端服务器来向我们的应用程序发送推送事件。这意味着您需要创建一个新的(可能)ExpressJS 项目,然后单独部署它。对于刚刚尝试推送通知的人来说,这将是一件令人头疼的事情。

Vercel 云函数来救援!云功能就像 Express 路由。他们可以运行代码并在您获取其 URL 时给您响应。Vercel 支持云功能;您只需要在api文件夹中创建文件。您将使用云功能与 MongoDB 进行交互,因为在客户端公开秘密从来都不是一件好事。

首先,确保您在MongoDB Atlas中有一个集群。MongoDB 有一个免费计划 ( M0),所以如果您还没有,请务必创建一个。现在,转到Atlas 仪表板侧栏中的Database Access选项卡。通过单击右侧的绿色按钮添加新的数据库用户。输入用户的详细信息(不要忘记密码),然后创建用户。

要连接到数据库,您需要连接字符串。将新用户和密码保存在某处,然后前往集群概览。单击右侧的连接按钮,然后选择连接您的应用程序作为连接方法。您应该看到一个类似于下面的连接字符串。

现在您有了连接字符串,您可以连接到数据库,但首先,您需要将当前应用程序部署到Vercel。最简单的方法是使用GitHub。

创建一个新的GitHub 存储库并将您的代码推送到其中。接下来,前往您的Vercel 仪表板并单击“新建项目”按钮。导入您的 GitHub 存储库,确保框架为Vite,并添加一个名为MONGODB_URL. 将其值设置为 MongoDB 数据库的连接字符串。

部署网站后,您需要将本地开发命令从 更改yarn dev为vercel dev. 运行命令后,如果系统要求您链接到现有项目,请单击yes

npm i -g vercel注意:如果您还没有安装 Vercel CLI,请确保安装。

vite像我一样,如果您在使用with时遇到问题vercel dev,请务必将项目的Development Command更改为Vercel Dashboardvite --port $PORT中的from 。vite

这将允许我们在本地使用具有正确环境变量的云函数。

让我们添加一个帮助文件,它允许我们在不打开太多连接的情况下访问 MongoDB。创建文件api/_mongo.js并将以下代码放入其中。api目录中以 a 为前缀的文件_不会视为云函数。这允许我们在单独的文件中添加助手和其他逻辑:

  1. const { MongoClient } = require("mongodb");
  2. const mongo = new MongoClient(process.env.MONGODB_URL);
  3. // Export the connection promise
  4. export default mongo.connect();

导出连接承诺而不是主客户端本身将防止我们拥有冗余连接,因为我们在无服务器平台中工作。

使用 CommonJS 而不是 ESModules

注意我是如何使用require而不是import? 这是因为,在撰写本文时,Vercel Cloud Functions支持 JavaScript 文件中的 ESModuleimport语句。相反,您需要使用 CommonJSrequire语句。

这里有一个问题。如果您看到package.json我们应用程序的 ,您会注意到它有一行"type": "module"。这意味着项目中的每个 JavaScript 文件都是一个 EsModule。这不是我们想要的,所以要将api目录中的所有文件都标记为 CommonJS 文件,这样我们就可以使用require语句,在其中创建api/package.json并添加这一行:

  1. {
  2. "type": "commonjs"
  3. }

这将允许我们在目录中使用require语句。api使用以下命令安装 MongoDB 连接驱动程序:

  1. # Don't forget to CD!
  2. cd api
  3. npm i mongodb # or use yarn

第 3 步:添加功能

到目前为止,跟踪器并没有真正起作用,所以让我们解决这个问题。

验证

对于身份验证,我们需要将用户输入的用户名存储在 MongoDB 数据库中。

创建一个文件/api/storeusername.js。这将是一个云功能,并将映射到
http://localhost:3000/api/storeusername. 将以下代码放入其中:

  1. const mongoPromise = require("../src/lib/mongo");
  2. // All cloud functions must export a function that takes a req and res object.
  3. // These objects are similar to their express counterparts.
  4. module.exports = async (req, res) => {
  5. // TODO
  6. };

接下来,像这样获取 MongoDB 客户端:

  1. module.exports = async (req, res) =>
  2. // Wait for the client to connect
  3. const mongo = await mongoPromise;
  4. }

username从请求的正文中提取:

  1. // ...
  2. const { username } = req.body;
  3. // Check if the username is valid
  4. if (typeof username !== "string" || !username.trim()) {
  5. res.status(400).json({ message: "Please send the username" });
  6. return;
  7. }

接下来,您需要将此用户名存储在数据库中:

  1. // Get the collection
  2. const usersCol = mongo.db().collection("users");
  3. // Check if the username already exists in the database
  4. if (await usersCol.findOne({ _id: username })) {
  5. res.status(400).json({ message: "User already exists!" });
  6. return;
  7. }
  8. // We want the username to be the identifier of the user
  9. await usersCol.insertOne({ _id: username });
  10. // Everything went well :)
  11. res.status(200).json({ message: "Username recorded" });

最后,这是api/storeusername.js文件的外观:

  1. const mongoPromise = require("./_mongo");
  2. module.exports = async (req, res) 
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/71598
推荐阅读
相关标签
  

闽ICP备14008679号