建立一个用于学习意大利语的全栈应用程序:supabase vs.黄蜂
#javascript #网络开发人员 #supabase #wasp

介绍

期望什么

在这篇博客文章中,我将解释如何使用两种不同的技术创建用于学习意大利短语的Phrase Tutor应用程序。我将共享一些代码片段,以显示使用WASP和Supabase构建应用所需的内容。

Phrase Tutor’s front-end

作为一名高级全栈开发人员,在构建许多侧项目方面具有经验,我更喜欢一个快速的开发周期。我喜欢在短短几天甚至几个小时内将想法变成POC。

我们将研究每种技术在构建全栈应用程序以及WaspSupabase excel时如何提供帮助。

我想快速学习意大利语

每当我出国旅行时,我都喜欢想象住在那个地方的感觉。例如,我通常不喜欢进行拥挤的公共交通工具,但是由于某种原因,当我在国外做时,它会给我带来欢乐。这就是我住在那儿的感觉。对于我来说,充分体验文化的最重要的事情之一就是学习语言,或者至少能够一直不说英语。

Pretending to be Italian

我和我的女朋友计划去意大利旅行,我想学习一些意大利语。我想到的是,最少的努力将是最简单的学习方法。我认为学习前100条意大利语短语将是一个好的开始。我有一个星期要做,如果我每天练习,学习100句话似乎是可行的。

学习方法

在高中时,我有一个学习历史事实和日期的系统,迅速称为“专注于您不知道的事物”。

这是其工作原理:

  1. 收集您想学习的事实库(例如,第二次世界大战何时开始?” - “ 1914”)。
  2. 问自己在游泳池中的每个问题。
  3. 如果您知道答案,请从池中删除事实。
  4. 如果您不知道答案,请将其放在池中。
  5. 重复较小的池直到没有更多的事实。

我为此制作了一个小应用程序,并与我的同学共享了一个小应用程序,但并没有走得更远。

现在,我想使用相同的方法来学习旅行的意大利短语。因此,作为一个更好的开发人员,我将制作一个适当的应用程序并在某个地方托管它ð

构建短语导师应用程序

我们将创建一个遵循上述方法的应用程序。该应用程序将向您显示一个短语,如果您选择“我知道”或“我不知道”,则可以告诉您是否知道翻译。

How the learning in the app should work

该应用程序将跟踪您的答案,并建议您要学习哪些短语

我两次构建了该应用程序:首先使用supabase,然后是黄蜂。 Supabase是一款全面的开源后端作为服务(BAA)产品,可在您的前端应用中增加超级大国。另一方面,黄蜂是一个开源框架,用于构建有助于保持样板较低的全栈应用程序。让我们看看它们如何比较。

初始supabase版本

制作初始版本时,我与vue.js合作,我用来创建第一个版本的Thrase Tutor应用程序。我首先收集一些短语。我在Google上搜索了“最佳的意大利短语要学习”,并遇到了一篇名为“ 100个意大利语的文字”的文章。 (从HTML提取短语后,我发现只有96个短语,但这对我来说仍然足够好。)

初始应用程序包含前端加载的JSON file中的短语。这完全是静态的,但起作用。

{
    "id": 1,
    "group": "general",
    "translations": {
        "en": "Yes",
        "it": "Si"
    }
}

我将其放在Cloudflare页面上,然后上线。

我向我的女朋友展示了它,但她不喜欢我使用的一些短语。如果我有一个数据库的后端来编辑短语。然后我有了一个想法:让我们添加一个数据库,然后使用Supabase

supabase是一种托管的后端解决方案,提供了许多免费的东西:PostgreSQL数据库和社交认证等。

Phrase Tutor built with Supabase

我使用非常简单的supabase UI设置数据库表。

我需要的桌子只有几个字段:

CREATE TABLE phrases (
    id bigint  NOT NULL,
    group character varying  NULL,
    translations_en text  NOT NULL,
    translations_it text  NOT NULL
);

然后,我必须用一些SQL播种数据库。使用supabase s ui,执行SQL语句很容易。您只需登录,打开SQL编辑器并在代码中粘贴:

INSERT INTO phrases(id,"group",translations_en,translations_it) VALUES (1,'general','Yes','Si');
INSERT INTO phrases(id,"group",translations_en,translations_it) VALUES (2,'general','No','No');
...

使用其Javascript SDK将Supabase集成到我现有的前端应用程序中很简单。如果您熟悉Firebase,那应该感觉相似。本质上,您可以在前端构建SQL查询,并在应用程序中使用所得数据。

使用SDK感觉很简单,我可以在没有太多麻烦的情况下从数据库中得到想要的东西。

const { data, error } = await supabase.from("phrases").select("*");

和那样,我的static vue.js应用程序具有一个数据库来依靠ð

使用Google添加登录名是在Supabase UI中启用它并设置客户端ID和客户端秘密变量的问题。为了使用Google触发登录过程,我依靠其JavaScript SDK依靠。

supabase.auth.signInWithOAuth({ provider: "google" });

真棒!我很高兴现在可以编辑短语,并且有一个我计划以后使用的登录功能。

将来,我计划在应用程序中添加更多语言,还允许注册用户贡献新的短语和翻译。我相信这将使该应用程序对语言学习者更有用。

和那样,我的应用程序从纯静态应用程序转移到带有数据库的应用程序和Google登录ðÖ

查看使用vue.js和supabase编写的已部署应用程序:https://phrase-tutor.pages.dev

查看源here

加入黄蜂和狗食

第二部分之前的一些背景:我今年早些时候开始在黄蜂工作。我真的很高兴能解决一种解决我关心的问题的技术:当我进行侧面项目时,我不喜欢每次从头开始写相同的乏味部分。我从以前的附带项目中复制和粘贴,但最终,代码片段变得旧且过时。

自然,我想通过重写我的一个项目来测试黄蜂。我决定看看黄蜂如何与短语导师项目一起使用。

WASP通过拥有一个易于理解的配置文件来工作,该文件称为main.wasp,该文件可以协调您的客户端和服务器功能。它的主要目的是使您富有成效,并专注于编写有趣的部分。感觉很像使用涵盖您整个应用的网络框架。

Phrase Tutor built with Wasp

让我们从创建数据模型开始。黄蜂在引擎盖下使用Prisma与您的数据库进行通信,这使得在不担心详细信息的情况下可以轻松管理数据库。这只是框架为我做出的众多选择之一,我感谢使用有效的设置的感觉。

我必须首先声明WASP配置文件中Prisma PSL所需的所有实体。

entity Phrase {=psl
  id Int @id @default(autoincrement())
  group String
  phrase String
  translations Translation[]
psl=}

entity Language {=psl
  id Int @id @default(autoincrement())
  name String @unique
  emoji String
  translations Translation[]
psl=}

entity Translation {=psl
  id Int @id @default(autoincrement())
  phraseId Int
  languageId Int
  translation String
  phrase Phrase @relation(fields: [phraseId], references: [id], onDelete: Cascade)
  language Language @relation(fields: [languageId], references: [id], onDelete: Cascade)
psl=}

我再次使用PostgreSQL数据库,您可以看到字段定义相似。

我通过定义三个表而不是一张表,从而提高了数据架构。我将Phrase的概念与LanguageTranslation的概念分开。这将使将来添加新语言变得更容易。

我使用prisma和Wasp action添加了一些短语:

export async function seedItalianPhrases(args, context) {
    const data = [
       {
            id: 1,
            group: "general",
            translations_en: "Yes",
            translations_it: "Si"
        },
        ...
    ]
    for (const phrase of seedPhrases) {
        await context.entities.Phrase.create({
            ...
        });
    }
}

现在,让我们看一下我需要做的事情来使数据从后端流到我的React应用程序。

首先,我在WASP配置文件中声明了一个查询:

app phraseTutor {
  ...
}
...

query fetchAllPhrases {
  fn: import { getAllPhrases } from "@server/queries.js",
  entities: [Phrase]
}

然后,我为后端编写了代码以获取短语。您会注意到这与我为使用Supabase SDK获取短语的代码非常相似,但是我必须包括translations关系,因为我们现在有多个表。

// My query got the Prisma entity through the context parameter
// which I just used to fetch all the phrases
export async function getAllPhrases(args, context) {
    return context.entities.Phrase.findMany({
        include: {
            translations: true
        }
    });
}

最后,我可以将查询导入我的React应用程序。它以一种自动处理缓存无效的方式进行设置,少要担心的一件事,这是很棒的ð

// Wasp relies on React Query in the background
const { data: phrases, isLoading } = useQuery(fetchAllPhrases);

让我们还为我们的应用程序增加了对Google Auth的支持。它涉及在WASP文件中声明您想要它,添加一些ENV变量并在React应用程序中使用。

我们通过在auth下添加google键来将其声明为WASP文件:

app phraseTutor {
  ...
  auth: {
    userEntity: User,
    externalAuthEntity: SocialUser,
    methods: {
      // Define we want the Google auth
      google: {
        // Optionally, we can adjust what is saved from the user's data
        getUserFieldsFn: import { getUserFields } from "@server/auth/google.js"
      }
    },
    onAuthFailedRedirectTo: "/"
  },
  ...
}

// Some of the entities needed for auth
entity User {=psl
  id Int @id @default(autoincrement())
  username String @unique
  password String
  profilePicture String
  externalAuthAssociations SocialUser[]
  createdAt DateTime @default(now())
psl=}

entity SocialUser {=psl
  id          Int       @id @default(autoincrement())
  provider    String
  providerId  String
  user        User      @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId      Int
  createdAt   DateTime  @default(now())
  @@unique([provider, providerId, userId])
psl=}

和 - 这样。现在,我们可以在我们的前端使用Google Authð

import { signInUrl as googleSignInUrl } from "@wasp/auth/helpers/Google";
...
const { data: user } = useAuth();

用黄蜂写一个全栈React and Express.js,感觉就像是一次有指导的经历。我不必过分专注于开发工具,构建或部署。

相反,我可以专注于短语导师工作所需的逻辑,并且大多数时候只运行wasp start。我确实需要编写一些额外的代码以使所有内容运行,但是我可以随意自定义此代码。

查看使用WASP构建的已部署项目:https://phrasetutor.com

查看源here

让我们比较一些功能

我想比较supabase和WASP的特征。思考做事及其优点和缺点的不同方式是一件好事。

获取数据 中启用
功能 supabase wasp
从API 使用supabase JS SDK查询数据库表 在WASP配置中声明查询,并使用Prisma JS SDK实现
自定义业务逻辑 编写自定义PostgreSQL过程或通过编写Edge功能 在WASP文件中声明操作并写入服务器端JS
定义数据库架构 可视编辑器或通过创建表查询 代码 - 编辑Prisma架构并提交更改
auth 在UI 在WASP文件中启用它
部署 supabase托管实例或自我主持人 部署任何地方,支持https://fly.io一行部署

使用supabase,我喜欢SDK感觉的熟悉程度,并且他们的UI使配置后端的一部分变得容易。我不需要考虑部署Supabase,因为我使用了他们的托管版本,但是在免费层次上不活动1周后,它确实暂停了。

另一方面,WASP感觉就像是我的React + Express.js + Prisma应用程序的胶水,我需要编写更多代码来完成工作。感觉更加明确,因为我将代码更接近我通常写的内容。我用wasp命令wasp deploy fly launch将其部署到fly.io,现在它在https://phrasetutor.com

上使用

结论

都是关于用例

为您的需求选择正确的解决方案可能很困难。这就是为什么重要的是尝试不同的选择并查看它们如何为您服务。在这种情况下,我比较了两个选项:supabase和Wasp。

supabase是一个不错的选择,如果您想要全面的开源BAAS产品,从而为您的前端应用增添了超级大国。它提供了很多免费的东西,例如PostgreSQL数据库和社交认证,这可以使开发更加轻松,更快。它还具有一个不错的SDK和UI,最终用户可以用来轻松定义其应用程序的配置。

WASP是用于构建全堆栈应用程序的开源框架,可帮助保持较低的样板。关于某些事情,例如定义您的身份实体,这更明确,但是当您拥有更高级用例时,这可能是一个加号。通过将黄蜂作为全堆栈应用程序的胶水,您可以拥有两全其美的最好的:开箱即用的开发和生产设置,同时仍允许您以自己喜欢的方式开发应用程序。

在短语导师的情况下,我喜欢使用Supabase和Wasp。但是,我确实与使用这两种技术有不同的感觉。有了Supabase,我觉得我的前端应用程序获得了即时的超级大国,现在它具有数据库和登录名,考虑到我必须付出的努力,这真是太好了。但是现在我有了一个黑盒依赖性,需要构建。

当我使用WASP重建短语辅导员时,感觉会有所不同,因为它是一个全栈应用程序。我对应用程序代码有了更多的控制权,因此我可以更改它并按照自己的意愿进行发展。我觉得我已经构建了一个可以朝任何方向增长的应用程序。尽管我不得不编写更多代码,但感觉就像未来需求的良好权衡。

要确定哪种选项最适合您,我建议您同时尝试并了解自己的感受。很容易设置这两个工具,看看它们是否对您有意义。

Grazie for reading 🙃

如果您尝试使用短语Tutor应用程序,请让我知道您的想法。您可以在Twitter上与我联系。我一直在寻找使它变得更好的方法。