Vue <3 GraphQL

2025-06-07

Vue <3 GraphQL

TL;DR:我做了这个:https://vuex-orm.github.io/vuex-orm-graphql/

这是我在 dev.to 上发表的第一篇文章,我想用它与这个令人惊叹的社区分享我当前的开源项目 :)

Vuex-ORM 的 GraphQL 插件和本文由德国i22 Digitalagentur GmbH提供支持。

旅程的开始

在我目前的业余项目中,我使用了 JSON/REST API,并通过 JSData 连接了前端单页应用程序。这种设置让我很不满意,还带来了很多问题。

然后我发现了Vuex-ORM,它提供了我在 Vue 中处理模型所需的一切,并且具有真正的响应式,速度极快,并且使用了 Vuex。我感觉应该用 Vuex-ORM 替换 JSData。但是:它没有插件可以连接 API。我不想在组件中写太多样板代码,也不喜欢在与 API 通信的细节上费劲。将单页应用程序与 API 集成可能会很麻烦。但其实不应该如此。

今年早些时候,我在新的全职工作中学习了 GraphQL。它真的太棒了。试用了一段时间后,我表示非常喜欢它,觉得我可以用 GraphQL 替换我业余项目中的 REST/JSON API。

后来,我在i22的全职工作中启动了一个项目,项目设置和我的业余项目非常相似,所以我决定尝试一下 Vuex-ORM。但我们承诺会使用 GraphQL(就像我们所有其他项目一样)。Vuex-ORM 没有 JSON/REST 插件,也没有 GraphQL 插件。我想,我可以写一个。我想,应该不难:我们已经有了模型定义和 GraphQL API,我只需将模型定义转换为 GraphQL 查询即可。我可以使用 apollo-client 库。这个插件应该能让与 API 的通信变得非常顺畅。无需样板代码,也无需摆弄 JSON 结构之类的。那就开始吧!

这比我想象的要困难得多,但经过几周的开发,我得到了一个基本可以工作的插件,它有一个最小的组件样板,只需要响应性和所有那些花哨的东西就可以了。

是时候进行下一步了:将我的副项目从 JSON/REST + JSData 迁移到 Vuex-ORM + GraphQL。在此期间,我发现了插件中的一些错误并修复了它们,编写了一些测试并添加了一些缺失的功能。

如今,经过几个月的微调、测试,以及Vuex-ORM 维护者Kia的大力帮助,我终于开发出了一个运行良好的 Vuex-ORM GraphQL 插件,它包含所有基本功能、文档,并且我目前正在使用的两个项目都在使用它。它运行得非常好。我现在对它非常满意 :)

现在是时候与社区分享我的成果了。在本文的剩余部分,我将向您展示 Vuex-ORM-GraphQL 插件的工作原理以及如何在您的项目中使用它。请记住:这只是一个基本示例。更多详细信息,请参阅Vuex-ORMVuex-ORM-GraphQL的文档。祝您使用愉快!

工作原理

我假设您有使用 Vue 和 GraphQL 的经验。

Vuex-ORM

首先我们必须设置 Vuex-ORM,这非常简单。

yarn add @vuex-orm/core
Enter fullscreen mode Exit fullscreen mode

然后在您的应用程序的某处创建一个store.js目录models

假设我们正在构建一个简单的博客。有postscomments。所以我们需要两个模型。让我们在新models目录中创建它们:

models/post.js

import { Model } from '@vuex-orm/core';
import Comment from './comment';

/**
 * The Vuex-ORM post model
 */
export default class Post extends Model {
    // Tell Vuex-ORM the path where the records should be stored in Vuex
    static entity = 'posts';

    // Tell Vuex-ORM-GraphQL to eagerly load all comments when we fetch a post.
    static eagerLoad = ['comments'];

    // Setup the fields and relations for Vuex-ORM
    static fields () {
        return {
            id: this.increment(),
            title: this.string(''),
            content: this.string(''),
            publishedAt: this.string(''),

            comments: this.hasMany(Comment, 'postId')
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

models/comment.js

import { Model } from '@vuex-orm/core';
import Post from './post';

/**
 * The Vuex-ORM comment model
 */
export default class Comment extends Model {
    // Tell Vuex-ORM the path where the records should be stored in Vuex
    static entity = 'comment';

    // Setup the fields for Vuex-ORM
    static fields () {
        return {
            id: this.increment(),
            author: this.string(''),
            content: this.string(''),
            publishedAt: this.string(''),

            postId: this.number(0),
            post: this.belongsTo(Post, 'postId')
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

如你所见,为 Vuex-ORM 设置模型非常简单。现在我们需要像这样设置 Vuex store:

store.js

import Vue from 'vue';
import Vuex from 'vuex';
import VuexORM from '@vuex-orm/core';

import Post from './models/post';
import Comment from './models/comment';


// Setup Vuex
Vue.use(Vuex);

// Setup Vuex-ORM database
const database = new VuexORM.Database();
database.register(Post, {});
database.register(Comment, {});

// Create Vuex Store and register the Vuex ORM plugin.
export default new Vuex.Store({
  plugins: [VuexORM.install(database)]
});
Enter fullscreen mode Exit fullscreen mode

之后,我们就可以在组件中创建新记录、查找、更改和删除它们了:

import Post from 'store/models/post';

Post.create({
  title: 'Example Blog Post',
  content: 'Lorem ipsum dolor sit amet',
  publishedAt: (new Date()).toISOString()
});

const allPosts = Post.all();
Enter fullscreen mode Exit fullscreen mode

Vuex-ORM GraphQL 插件

下一步,我们将为 Vuex-ORM 设置我的新 GraphQL 插件,这非常简单,因为该插件隐藏了 apollo-http-link、apollo-client 等所有复杂的功能。它设计为安装后即可使用:

yarn add @vuex-orm/plugin-graphql
Enter fullscreen mode Exit fullscreen mode

像这样改变store.js

// ...
database.register(Post, {});
database.register(Comment, {});

// --8<-------------
// This is the new part
import installVuexORMGraphQL from '@vuex-orm/plugin-graphql';
VuexORM.use(installVuexORMGraphQL, {
  database: database,
  debug: process.env.NODE_ENV !== 'production'
});
// --8<-------------

// Create Vuex Store and register the Vuex ORM plugin.
export default new Vuex.Store({
  plugins: [VuexORM.install(database)]
});
Enter fullscreen mode Exit fullscreen mode

这里没什么特别的,我们只需将 Vuex-ORM-GraphQL 插件注册为 Vuex-ORM 插件并传递数据库即可。无需执行其他操作。正如我所说:设置非常简单 ;)

存储与持久化操作

在使用带有 GraphQL 插件的 Vuex-ORM 时,您必须区分两种类型的 Vuex 操作:

  • 存储操作:从 Vuex Store 检索数据或将数据保存到 Vuex Store(Vue Component <--> Vuex Store
  • 持久化操作:从 GraphQL API 加载数据或将数据持久化到 GraphQL API(Vuex Store <--> GraphQL Server

下表列出了所有操作及其作用:

增删改查 仅限 Vuex 持久化到 GraphQL API
find(),,all()query() fetch()
创造 create()或者insert() $persist()
更新 $update() $push()
删除 $delete() $destroy()

例子

设置完成后,我们可以使用 Vuex-ORM 从 GraphQL API 获取数据并以响应式方式显示它:

<template>
  <div class="blog">
    <article v-for="post in posts" :key="post.id" class="blog__post">
      <h2>{{post.title}}</h2>
      <small>{{post.publishedAt}}</small>

      <p>{{post.content}}</p>

      <a href="#" @click.prevent="destroy(post)">Delete this post</a>

      <hr />

      <section class="comments">
        <h3>Comments</h3>

        <article v-for="comment in posts.comments" :key="comment.id" class="comments__comment">
          <h4>From {{comment.author}}</h4>
          <p>{{comment.content}}</p>
        </article>
      </section>
    </article>
  </div>
</template>

<script>
  import Post from 'data/models/post';

  export default {
    computed: {
      // Returns all posts with reactivity.
      posts: () => Post.all()
    },

    async mounted() {
      // Load all posts form the GraphQL API.
      await Post.fetch();
    },

    methods: {
      // Deletes the post from Vuex Store and from the server.
      async destroy(post) {
        post.$deleteAndDestroy();
      }
    }
  }
</script>
Enter fullscreen mode Exit fullscreen mode

这就是从服务器加载博客文章和评论、显示它们并允许用户删除文章所需的全部代码。

GraphQL 查询

上面的代码生成以下 GraphQL 查询fetch

query Posts {
  posts {
    nodes {
      id
      content
      title
      publishedAt

      comments {
        nodes {
          id
          author
          content
          publishedAt
          postId
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

以及以下 GraphQL 突变destroy

mutation DeletePost($id: ID!) {
  deletePost(id: $id) {
    id
  }
}
Enter fullscreen mode Exit fullscreen mode

结论

还有很多工作要做:代码在某些地方比较混乱,缺少一些测试,订阅功能尚未实现,配置性还有待提升,文档也尚未完成。但我认为是时候与社区分享我的工作,收集反馈,并希望获得一些贡献,将插件升级到稳定的 1.0.0 版本。

谢谢阅读。

附言:这个副项目即将上线。到时候我会发一篇帖子分享给大家 ;)

文章来源:https://dev.to/phortx/vue-3-graphql-kj6
PREV
Zsh + Antigen + Oh my Zsh = 美观、强大、健壮的 Shell Zsh Antigen Oh my Zsh
NEXT
如何永久免费获得 2 台 Oracle 云服务器