发布于 2026-01-06 5 阅读
0

如何使用 Svelte 和 GraphQL 构建全栈无服务器应用程序 AWS AI LIVE!

如何使用 Svelte 和 GraphQL 构建全栈无服务器应用程序

AWS AI 直播!

在本教程中,你将学习如何使用Svelte.js、GraphQL 和 Fauna构建一个全栈无服务器应用程序。你将构建一个类似于Dev.tohashnode.comMedium 的博客平台。用户可以登录你的应用程序,创建新文章,编辑和删除自己的文章。

我们将使用以下技术栈。

  • Svelte.js(Sveltekit
  • GraphQL
  • 数据库动物群
  • 部署(Vercel 或 Netlify)

🤖 您可以在以下GitHub链接中找到最终代码。

创建一个新的 Svelte 应用

首先,创建一个新的 Svelte 应用。在终端中运行以下命令。

npm init svelte@next blogApp
Enter fullscreen mode Exit fullscreen mode

Svelte CLI 提供了一些选项来定制我们的应用程序。请选择以下选项。

✔ Which Svelte app template? › Skeleton project

✔ Use TypeScript? … No

✔ Add ESLint for code linting?  Yes

✔ Add Prettier for code formatting? Yes

使用以下命令运行我们新创建的应用程序。

cd blogApp
npm i
npm run dev
Enter fullscreen mode Exit fullscreen mode

运行示例应用程序预览

在本教程中,我们将主要关注应用程序的功能,不会过多涉及样式设计。让我们开始创建一个简单的导航栏组件。创建一个新文件src/lib/Nav.svelte,并将以下代码添加到其中。

// src/lib/Nav.svelte

<nav>
  <a href="/">Home</a>
  <a href="/login">Login</a>
  <a href="/register">Register</a>
</nav>
Enter fullscreen mode Exit fullscreen mode

接下来,我们来创建一个布局文件。新建一个文件src/routes/__layout.svelte,并添加以下代码。

// src/routes/__layout.svelte
<script>
    import Nav from '$lib/Nav.svelte';
  </script>

<Nav />
<slot></slot>
Enter fullscreen mode Exit fullscreen mode

现在运行应用程序时,Navbar每个页面都会出现一个组件。

带有导航栏组件的应用程序

设置 Svelte GraphQL 客户端

你的 Svelte 应用将使用 GraphQL 后端服务。有很多流行的库可用于在 Svelte 中使用 GraphQL。这个@urql/svelte库是其中最流行的库之一。接下来,我们来配置它。

运行以下命令将库添加到您的项目中。

npm i @urql/svelte --save
Enter fullscreen mode Exit fullscreen mode

接下来创建一个新文件src/client.js,并添加以下代码片段。

// src/client.js

import { createClient } from '@urql/svelte';

export default createClient({
  url: 'https://graphql.us.fauna.com/graphql',

  // For DB in other zone use the following url
    // EU: https://graphql.eu.fauna.com/graphql
  // Classic: https://graphql.fauna.com/graphql

  fetchOptions: () => {
    const token = import.meta.env.VITE_PUBLIC_FAUNA_KEY;
    return {
      headers: { authorization: token ? `Bearer ${token}` : '' },
    };
  },
}); 
Enter fullscreen mode Exit fullscreen mode

现在我们已经准备好从GraphQL后端查询数据了。接下来,让我们开始设置数据库。

设置数据库

如果您还没有Fauna账户,请立即创建一个。Fauna 是一个分布式无服务器数据库,它使用原生 GraphQL API。

前往动物区系控制面板并创建一个新数据库。

动物群创建新数据库

现在您可以定义 GraphQL schema 了。以下 ULM 图描述了如何在您的应用程序中对数据进行建模。在这个应用中,您有用户,每个用户可以发布多条帖子。这是用户与帖子has_many之间的关系UserPost

数据库关系

返回代码页面,schema.graphql在根目录下创建一个新文件。添加以下代码。

# schema.graphql

type User {
  username: String!
  email: String!
  posts: [Post!] @relation
}

type Post {
  title: String!
  content: String!
  author: User!
}

type Query {
  listPosts: [Post]
}
Enter fullscreen mode Exit fullscreen mode

接下来,将模式文件上传到您的 Fauna 数据库。前往 Fauna 控制面板,选择 GraphQL 并导入模式文件。导入该schema.graphql文件。

将架构上传到 Fauna

请注意,方案上传后,您将看到一个 GraphQL Playground。您可以在此 Playground 中添加、修改和调试您的 GraphQL API。

GraphQL Playground 概述

接下来,我们向数据库添加一些数据。在 GraphQL playground 中运行以下 mutation 来创建一个新用户。

mutation CreateNewUser {
  createUser(data: {
    username: "shadid"
    email: "shadid120@email.com"
  }) {
    _id
    username
    email
  }
}
Enter fullscreen mode Exit fullscreen mode

在 GraphQL Playground 上运行的 Mutation CreateNewUser

同样地,创建一个新帖子。在 GraphQL playground 中运行以下 mutation 来创建一个新帖子。

mutation CreatePost {
  createPost(data: {
    title: "Hello worlds"
    content: "Some content"
    author: {
      **connect: "321522241336508481"**
    }
  }) {
    _id
    title
    content
    author {
      email
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

请注意,我们使用了“作者 > 连接”字段。您需要在此处添加上一个 mutation 中的 userId。这将把用户与文章关联起来。因此,这篇文章的作者将是您在第一个 mutation 中创建的用户。

在 GraphQL Playground 上运行的 post mutation

从 Svelte 应用查询数据

接下来,我们从 Svelte 应用中查询数据。首先,我们需要指定一个角色,并生成一个键,以便前端与数据库通信。

前往 Fauna 控制面板。选择“安全”>“角色”>“新建自定义角色”。

创建新的自定义角色

给你的角色命名,并授予其对集合的读取权限User。同时授予其对索引和索引的Post读取权限post_author_by_userlistPosts

授予自定义角色权限

现在导航至“安全” > “钥匙” > “新建钥匙”。

创建新密钥

为您的角色创建一个新密钥SvelteApp

与角色相关的关键信息

生成新密钥

接下来,复制生成的密钥。.env在应用程序根目录下创建一个新文件,并将该密钥添加为环境变量。

# .env
VITE_PUBLIC_FAUNA_KEY=<Your Key Here>
Enter fullscreen mode Exit fullscreen mode

请注意,此密钥为公钥,将对前端公开。因此,与此密钥关联的角色仅具有读取权限。

现在,让我们在首页上从数据库中导入所有文章。请将以下代码添加到您的src/routes/index.js文件中。

<script lang="js">
    import { operationStore, query, setClient} from '@urql/svelte';
    import client from '../client'
    setClient(client);

  const allPosts = operationStore(`
    query GetAllPosts($size: Int!, $cursor: String) {
      listPosts(_size: $size, _cursor: $cursor) {
        data {
          _id
          title
          author {
            email
          }
        }
      }
    }
  `,
  { size: 100 },
  { requestPolicy: 'network-only' }
  );

    query(allPosts);

</script>

<h1>Posts</h1>

{#if $allPosts.fetching}
<p>Loading...</p>
{:else if $allPosts.error}
<p>Oh no... {$allPosts.error.message}</p>
{:else}

{#each $allPosts.data.listPosts.data as post}

<div class="post-wrap">
  <a href={`/posts/${post._id}`}>
    <div>{post.title}</div>
  </a>
  <span>by {post.author.email}</span>
</div>

{/each}

{/if}

<style>
  .post-wrap {
    margin-bottom: 1rem;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

重启应用程序。你会发现现在所有帖子都位于应用程序的根 URL 下。

应用显示索引路径上的所有帖子

请注意,当您选择帖子时,应用会将您带到/post/:id路线规划页面。您可以在该路线规划页面中查看各个帖子。接下来,我们来创建这条路线规划页面。

创建一个新文件routes/posts/[id].svelte,并添加以下代码。

// routes/posts/[id].svelte

<script lang="js">
  import { operationStore, query, setClient} from '@urql/svelte';
  import { page } from '$app/stores';
    import client from '../../client'
    setClient(client);

  const currentPost = operationStore(`
    query GetPostById($id: ID!) {
      findPostByID(id: $id) {
        _id
        title
        content
        author {
          email
        }
      }
    }
  `,
  { id: $page.params.id }
  )

  query(currentPost)

</script>

{#if $currentPost.fetching}
<p>Loading...</p>
{:else}

<h2>{$currentPost.data.findPostByID.title}</h2>
<p>By <b>{currentPost.data.findPostByID.author.email}</b></p>
<p>{$currentPost.data.findPostByID.content}</p>
{/if}
Enter fullscreen mode Exit fullscreen mode

身份验证和授权

接下来,我们来为应用程序添加身份验证功能。我们可以使用fauna-gql-upload`and`fauna-graphql-tool库轻松添加身份验证。首先,让我们将这些依赖项添加到项目中。

npm i @fauna-labs/graphql-tool fauna-gql-upload --save-dev
Enter fullscreen mode Exit fullscreen mode

这些库是自动化脚本,您需要从 Fauna 获取管理员密钥才能运行这些工具。

前往动物区系控制面板。

选择“安全”>“钥匙”>“新建钥匙”。

创建新密钥

创建一个新的管理员密钥。确保角色设置为管理员。

管理员密钥

请勿与任何人共享此管理员密钥,也不要将其与您的应用程序一起部署。管理员密钥只能与自动化/迁移工具一起使用。

将管理员密钥添加到.env变量中。确保您的.env文件已添加到 .gitignore 列表中。

##.env
VITE_PUBLIC_FAUNA_KEY=<Fauna Public Key>
FGU_SECRET=<Your Admin Key>

Enter fullscreen mode Exit fullscreen mode

接下来,您需要对 GraphQL schema 进行以下更改。

type User **@auth(primary: "email")** {
  username: String!
  email: String!
  posts: [Post!] @relation
}

type Post **@protected(membership: "User", rule: ["read", "write", "create"])** {
  title: String!
  content: String!
  author: User!
}

type Query {
  listPosts: [Post]
}
Enter fullscreen mode Exit fullscreen mode

请注意,在之前的代码块中,我们@auth向 User 集合添加了一个指令。这意味着我们将使用 User 集合进行身份验证。该primary指令定义了用于注册和登录用户的字段。在本例中,该指令为 `<your_email_name>` email。因此,用户可以使用其电子邮件地址和密码登录。

请注意,@protectedPost 集合* 中添加了一条指令 * 此指令定义了访问模式。已登录用户可以撰写和创建新帖子。

将这些更改添加到架构后,打开该package.json文件,并在脚本部分添加以下代码片段。

// package.json

{
 ...
 "script": {
   ...
   "fgu": "fgu",
   "fgt": "fgt"
 }
}
Enter fullscreen mode Exit fullscreen mode

我们在这里添加这些脚本,以便我们可以从 npm 运行fauna-graphql-tool(fgt) 和fauna-gql-upload(fgu)。

fgt它会获取您的 GraphQL schema,并将 schema 编译成各种数据库资源(例如集合、用户定义的函数、身份验证规则),然后fgu将这些资源上传到 Fauna。

最后,在终端中运行以下命令。

npm run fgt && npm run fgu
Enter fullscreen mode Exit fullscreen mode

/fauna请注意,系统会生成一个包含所有资源的新文件夹。

生成的文件

  • 📗 专业提示:

    请注意,运行脚本后会创建一个名为 `<path>` 的新文件夹/fauna。您可以打开此文件夹,查看自动化脚本创建的各种功能和角色。如果您想进一步自定义身份验证规则,请随时在此处修改逻辑。

如果您想了解这些资源的工作原理,请查阅Fauna JavaScript 驱动程序的相关文档。

现在,当你回到 Fauna 中的 GraphQL playground 时,你会注意到mutation 对你register来说是可用的。login

显示突变

最后,前往“安全”>“角色”>“SvelteRole”,并将您的角色调用权限授予这些新生成的函数。user_by_email同时,请确保授予对索引的读取权限,因为登录函数会使用此索引。

配置权限

用户注册表单

接下来,我们来创建用户注册表单。创建一个新文件src/routes/register.svelte并添加以下代码。

// src/routes/register.svelte

<script lang="js">
  import { setClient, mutation } from '@urql/svelte';
  import client from '../client'
  import { goto } from '$app/navigation';

  setClient(client);

  const registerMutation = mutation({
    query: `
      mutation ($email: String!, $password: String!) {
        register(email: $email, password: $password) {
          email
          _id
        }
      }
    `,
  });

  async function onSubmit(e) {
    const formData = new FormData(e.target);

    const data = {};
    for (let field of formData) {
      const [key, value] = field;
      data[key] = value;
    }
    const { email, password } = data;
    const resp = await registerMutation({ email, password })
    if (resp.data.register) {
      goto('/');
    } 
    if(resp.error) {
      alert(resp.error.message);
      console.log(resp.error);
    }
  }
</script>

<div class="wrap">
  <h3>Register New User</h3>
  <form on:submit|preventDefault={onSubmit}>
    <div>
        <label for="name">Email</label>
        <input
          type="text"
          id="email"
          name="email"
          value=""
        />
    </div>
    <div>
      <label for="name">Password</label>
      <input
        type="password"
        id="password"
        name="password"
        value=""
      />
    </div>
    <button class="button is-light" type="submit">Register</button>
  </form>
</div>
Enter fullscreen mode Exit fullscreen mode

前面的代码块中有一个简单的表单组件。表单提交后,register会执行 mutation 操作,并注册一个新用户。

用户登录表单

接下来,我们来创建一个用户登录表单。我们可以将用户会话保存在浏览器 cookie 中。这个js-cookie库可以轻松实现这一点。在终端中运行以下命令即可添加此库。

npm i js-cookie --save
Enter fullscreen mode Exit fullscreen mode

创建一个新文件src/routes/login.svelte,并添加以下代码。

<script>
  import { setClient, mutation } from '@urql/svelte';
  import client from '../client';
  import Cookies from 'js-cookie';
  import { goto } from '$app/navigation';

  setClient(client);

  const loginMutation = mutation({
    query: `
      mutation ($email: String!, $password: String!) {
        login(email: $email, password: $password) {
          secret
          ttl
          data {
            _id
            email
          }
        }
      }
    `,
  });
  async function onSubmit(e) {
    const formData = new FormData(e.target);

    const data = {};
    for (let field of formData) {
      const [key, value] = field;
      data[key] = value;
    }
    const { email, password } = data;
    const resp = await loginMutation({ email, password })

    if(resp.data.login.data) {
      Cookies.set(
        'MY_BLOG_APP_TOKEN', 
        JSON.stringify({
          id: resp.data.login.data._id,
          secret: resp.data.login.secret
        }), 
        { expires: resp.data.login.data.ttl }
      );
      alert('Login Successful');
      goto('/')
    }
  }
</script>

<div>
  <h3>Login Form</h3>
  <form on:submit|preventDefault={onSubmit} >
    <div>
      <label for="name">Email</label>
      <input
        type="text"
        id="email"
        name="email"
        value=""
      />
    </div>
    <div>
      <label for="name">Password</label>
      <input
        type="password"
        id="password"
        name="password"
        value=""
      />
    </div>
    <button type="submit">Submit</button>
  </form>
</div>
Enter fullscreen mode Exit fullscreen mode

前面的代码块中有一个简单的表单组件。表单提交后,login会触发 mutation。登录成功后,Fauna 会返回一个新的 token。这个 token 是经过身份验证的用户 token。我们会js-cookie将此 token 存储在浏览器 cookie 中。

创建新帖子

在我们的应用程序中,已登录用户可以创建新帖子。请clientWithAuthToken在您的client.js文件中创建一个名为 `createPosts` 的新函数。您可以传入从会话 cookie 中获取的身份验证令牌,该函数将使用该会话令牌设置 GraphQL 客户端。

// src/client.js

export const clientWithAuthToken = token => createClient({
  url: 'https://graphql.us.fauna.com/graphql',
  fetchOptions: () => {
    console.log('token', token);
    return {
      headers: { authorization: token ? `Bearer ${token}` : '' },
    };
  },
});
Enter fullscreen mode Exit fullscreen mode

接下来,我们来创建一个用户可以发布新帖子的页面。

创建一个新文件src/routes/posts/new.svelte,并将以下代码添加到该文件中。


// src/routes/posts/new.svelte

<script lang="js">
  import Cookies from 'js-cookie';
  import { setClient, mutation } from '@urql/svelte';
  import { clientWithAuthToken } from '../../client';
  import { goto } from '$app/navigation';

  let userSession = Cookies.get('MY_BLOG_APP_TOKEN');
  let authorId;

  if(userSession) {
    const { secret, id } = JSON.parse(userSession);
    authorId = id;
    setClient(clientWithAuthToken(secret));
  }

  const newPost = mutation({
    query: `
    mutation CreatePost($title: String!, $content: String! $authorId: ID!) {
      createPost(data: {
        title: $title
        content: $content
        author: {
          connect: $authorId
        }
      }) {
        _id
        title
        content
      }
    }
    `,
  });

  async function onSubmit(e) {
    const formData = new FormData(e.target);

    const data = {};
    for (let field of formData) {
      const [key, value] = field;
      data[key] = value;
    }

    const { content, title } = data;
    try {
      console.log('authorId', authorId);
      if(!authorId) {
        alert('You must be logged in to create a post');
        return;
      }
      const resp = await newPost({ title, content, authorId }); 
      if(resp.data.createPost) {
        alert('Post created successfully')
        goto('/')
      }
    } catch (error) {
      console.log(error);
    }
  }
</script>

<div>
  <h3>New Post</h3>
  {#if !userSession}
    <p class="login-promt">You must be logged in to create a post</p>
  {/if}
  <form on:submit|preventDefault={onSubmit} >
    <div class="input-blocks">
      <label for="name">Title</label>
      <input
        type="text"
        name="title"
        value=""
      />
    </div>
    <div class="input-blocks">
      <label for="name">Content</label>
      <textarea
        type="text"
        name="content"
        value=""
      />
    </div>
    <button type="submit">Submit</button>
  </form>
</div>

<style>
  .input-blocks {
    display: flex;
    flex-direction: column;
    max-width: 300px;
    margin-bottom: 1em;
  }
  .login-promt {
    color: coral;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

在之前的代码块中,当用户提交表单时,createPostmutation 会触发。请注意,我们使用会话令牌clientWithAuthToken来设置 GraphQL 客户端。您可以从浏览器 cookie 中获取会话令牌,并使用它来设置 GraphQL 客户端。如果用户未登录或会话令牌已过期,则此 mutation 将无法正常工作。

删除帖子

让我们添加删除帖子的功能。创建一个新组件src/lib/Delete.svelte

并添加以下代码。

// src/lib/Delete.svelte

<script lang="js">
  import Cookies from 'js-cookie';
  import { clientWithAuthToken } from '../client';
  import { setClient, mutation } from '@urql/svelte';
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';

  let userSession = Cookies.get('MY_BLOG_APP_TOKEN');
  if (userSession) {
    setClient(clientWithAuthToken(userSession))
    const {secret } = JSON.parse(userSession);
    setClient(clientWithAuthToken(secret));
  }

  const deletePost = mutation({
    query: `
      mutation DeletePost($id: ID!) {
        deletePost(id: $id) {
          _id
          title
        }
      }
    `
  })

  async function handleDelete() {

    const { data, error } = await deletePost({ id: $page.params.id });

    if(error) {
      console.log('error', error);
      alert('error', error.message);
      return;
    }

    if(data.deletePost) {
      alert('Post deleted');
      goto('/')
    }

  }
</script>

<button on:click|preventDefault={handleDelete} disabled={!userSession}>Delete</button>
Enter fullscreen mode Exit fullscreen mode

此组件渲染一个按钮。当按钮被选中时,它会deletePost使用已认证用户的令牌触发 mutation。

将此组件添加到您的src/routes/posts/[id].svelte页面。

<script lang="js">
 ...
</script>

...
<Delete />
{/if}
Enter fullscreen mode Exit fullscreen mode

但是请注意,当您点击该按钮时,会收到“权限被拒绝”的提示信息。这是因为我们尚未设置删除权限。

再次前往 Fauna 控制面板,然后选择“安全”>“角色”>“用户角色”。

定义用户角色

Post收藏夹中选中删除选项并选择保存。

发布权限

🤔 如果您只想让帖子所有者删除帖子该怎么办?添加此规则非常简单。从帖子下拉菜单中选择删除规则即可。

谓词权限

在谓词规则中添加以下代码片段。该谓词规则定义只有帖子作者才能删除帖子。

Lambda("ref", Equals(
  Identity(), // logged in user
  Select(["data", "author"], Get(Var("ref")))
))
Enter fullscreen mode Exit fullscreen mode

编辑帖子

接下来,我们来添加文章编辑功能。请创建一个新组件/src/lib/Edit.svelte并添加以下代码。

// /src/lib/Edit.svelte
<script lang="js">
  import { operationStore, query, setClient } from '@urql/svelte';
  import { page } from '$app/stores';
    import client from '../../client'
  import Delete from '$lib/Delete.svelte';
  import Edit from '$lib/Edit.svelte';

    setClient(client);

  const currentPost = operationStore(`
    query GetPostById($id: ID!) {
      findPostByID(id: $id) {
        _id
        title
        content
        author {
          email
        }
      }
    }
  `,
  { id: $page.params.id },
  { requestPolicy: 'network-only' }
  )

  query(currentPost)

  export let post = null;

  currentPost.subscribe(({data}) => {
    if(data) {
      post = data.findPostByID;
    }
  })

</script>

{#if $currentPost.fetching}
<p>Loading...</p>
{:else}

<h2>{$currentPost.data.findPostByID.title}</h2>
<p>By <b>{currentPost.data.findPostByID.author.email}</b></p>
<p>{$currentPost.data.findPostByID.content}</p>
<Edit post={post}/>
<Delete />
{/if}
Enter fullscreen mode Exit fullscreen mode

此组件是一个基础表单组件,其中的数据已预先填充posts/[id].svelte。表单提交时,此组件会触发编辑帖子变更。

将此组件添加到您的src/routes/posts/[id].svelte文件中。

<script lang="js">
    import Edit from '$lib/Edit.svelte'; 
  ... 
  export let post = null;

  currentPost.subscribe(({data}) => {
    if(data) {
      post = data.findPostByID;
    }
  })
</script>

...
<Edit post={post}/>
{/if}
Enter fullscreen mode Exit fullscreen mode

修改完成后,文件中的代码src/routes/posts/[id].svelte应如下所示。

// src/routes/posts/[id].svelte
<script lang="js">
  import { operationStore, query, setClient } from '@urql/svelte';
  import { page } from '$app/stores';
    import client from '../../client'
  import Delete from '$lib/Delete.svelte';
  import Edit from '$lib/Edit.svelte';

    setClient(client);

  const currentPost = operationStore(`
    query GetPostById($id: ID!) {
      findPostByID(id: $id) {
        _id
        title
        content
        author {
          email
        }
      }
    }
  `,
  { id: $page.params.id },
  { requestPolicy: 'network-only' }
  )

  query(currentPost)

  export let post = null;

  currentPost.subscribe(({data}) => {
    if(data) {
      post = data.findPostByID;
    }
  })

</script>

{#if $currentPost.fetching}
<p>Loading...</p>
{:else}

<h2>{$currentPost.data.findPostByID.title}</h2>
<p>By <b>{currentPost.data.findPostByID.author.email}</b></p>
<p>{$currentPost.data.findPostByID.content}</p>
<Edit post={post}/>
<Delete />
{/if}
Enter fullscreen mode Exit fullscreen mode

更新模板以反映用户身份验证状态

目前,我们的应用模板在用户登录状态下不会改变。让我们来改变这一点。

创建一个新文件src/store.js。在该文件中创建一个新的可写存储区,用于保存用户会话数据。将以下代码添加到该文件中。

import { writable } from 'svelte/store';

export const userSession = writable(null); 
Enter fullscreen mode Exit fullscreen mode

接下来,每当用户登录时,将用户信息写入此存储。请对文件进行以下代码更改src/routes/login.svelte

<script>
  ...
  import { userSession } from '../store';
  ...
  async function onSubmit(e) {
    ...
    if(resp.data.login.data) {
      ...
      userSession.update(() => ({
        email,
        id: resp.data.login.data._id,
        secret: resp.data.login.secret
      }));
      alert('Login Successful');
      goto('/')
    }
  }
</script>
Enter fullscreen mode Exit fullscreen mode

最后,使用以下代码更新src/lib/Nav.svelte文件。以下代码块用于监听应用商店的任何更改。如果用户已登录,则应用会显示注销表单;否则,会显示登录和注册链接。

<script lang="js">
  import { userSession } from '../store.js';
  import Cookies from 'js-cookie';
  let user;
  userSession.subscribe(val => {
    user = val;
  });

  function logout() {
    userSession.update(() => null);
    Cookies.remove('MY_BLOG_APP_TOKEN');
  }
</script>

<nav>
  <a href="/">Home</a>
  {#if user}
  <!-- svelte-ignore a11y-invalid-attribute -->
  <a href="#" on:click={logout}>Logout</a>
  {:else}
  <a href="/login">Login</a>
  <a href="/register">Register</a>
  {/if}
  <hr />
</nav>
Enter fullscreen mode Exit fullscreen mode

部署

维塞尔

现在,我们的应用程序已准备就绪,可以上线了。您可以使用 Vercel 轻松部署 Svelte 应用程序。如果您还没有 Vercel 帐户,请创建一个新帐户。接下来,运行以下命令并按照说明操作。

npx vercel --prod
Enter fullscreen mode Exit fullscreen mode

Netlify

请按照以下文章中的步骤进行 Netlify 部署。

https://dev.to/danawoodman/deploying-a-sveltekit-app-to-netlify-5dc3

好了,就到这里。希望这篇文章对您有所帮助,让您对使用 Svelte 和 GraphQL 开发全栈无服务器应用程序有了全面的了解。如果您有任何反馈,欢迎在评论区留言。如果您有任何问题,欢迎随时通过我的 Twitter @HaqueShadid 联系我。

文章来源:https://dev.to/shadid12/how-to-build-a-full-stack-serverless-application-with-svelte-graphql-and-fauna-5427