villus Documentation

repository·main·Indexed 21 days ago

https://github.com/logaretm/villus

A lightweight, fast GraphQL client specifically designed for Vue.js (supporting Vue 3.0+ and 2.7+). It provides essential features such as caching, batching, and deduplication with a minimal footprint. The library includes composables like useQuery, useMutation, and useSubscription for reactive data fetching, as well as a standalone createClient() for non-reactive contexts.

Tokens
31.2K
Snippets
117
Records
131
Agent score
73%

What's inside villus

  1. Introduction to Villus

    main

    villus is a minimal GraphQL client designed for Vue.js. It provides a lightweight alternative to Apollo Client, focusing on flexibility and a small footprint while providing essential quality-of-life features like query caching out of the box. It is suitable for both small projects and large, complex applications.

    Key features include:

    • Minimal & Tiny: Small footprint with only what you need to query GraphQL APIs.
    • Caching: Simple and convenient query caching enabled by default.
    • TypeScript Support: Written in TypeScript for better developer experience.
    • Vue Integration: Provides minimal Vue.js components and full Composition API support.
  2. How reactive queries work in useQuery

    main

    You can make a query reactive by passing a Ref or ComputedRef as the query argument. useQuery will automatically watch these for changes and re-fetch the query whenever the value updates.

    Note: Objects created with reactive() are not supported as reactive queries; you must use Ref or ComputedRef (e.g., via computed()).

    ```vue\n<script setup>\nimport { computed, ref } from 'vue';\nimport { useQuery } from 'villus';\n\nconst id = ref(1);\n\n// Create a computed query that reacts to 'id'\nconst FetchTodo = computed(() => {\n  return `query FetchTodo {\n      todo (id: ${id.value}) {\n        text\n      }\n    }\n  `;\n});\n\nconst { data } = useQuery({\n  query: FetchTodo,\n});\n\n// Changing the ref triggers an automatic refetch\nid.value = 2;\n</script>\n```
  3. Understand the Fetch Plugin in Villus

    main

    The fetch plugin is a critical component of the Villus pipeline. While Villus uses a pipeline of plugins to process GraphQL operations, the fetch plugin is responsible for the actual execution of queries and mutations against your GraphQL API.

    Note: The fetch plugin is included by default in any Villus client unless you explicitly override the plugin configuration.

  4. How reactive queries work

    main

    Villus supports reactive queries by watching the query property itself. If you pass a computed property or a ref as the query argument, Villus will automatically re-fetch the query whenever the underlying query string/AST changes.

    <script setup>
    import { computed, ref } from 'vue';
    import { useQuery } from 'villus';
    
    const id = ref(1);
    
    // The query is reactive; changing id.value triggers a re-fetch
    const FetchTodo = computed(() => {
      return `query FetchTodo { todo (id: ${id.value}) { text } }`;
    });
    
    const { data } = useQuery({
      query: FetchTodo,
    });
    </script>
  5. Use Query Tags to manage cache

    main

    You can associate queries with an array of string tags. These tags allow you to manage cache invalidation and refetching, typically in coordination with mutations:

    • Cache Clearing: A mutation configured with clearCacheTags containing a specific tag will clear the cache for all queries marked with that same tag.
    • Automatic Refetching: Mutations can be configured to automatically refetch all queries that share a specific tag after the mutation completes.

    To tag a query, pass the tags array in the useQuery options object.

    const { data } = useQuery({
      query: GetPosts,
      tags: ['all_posts'],
    });
  6. Mock network requests in Villus tests

    main

    To test components that use useQuery or useMutation, you need to mock the GraphQL API responses. There are two primary approaches:

    1. Mocking the fetch function: A simpler approach where you intercept the global fetch and return a manual response.
    2. Using MSW (Mock Service Worker): The recommended approach. MSW allows you to mock an API server at the network level, which enables testing GraphQL error responses and provides a testing environment that closely mimics real-world behavior.
  7. How Villus plugins work

    main

    Plugins are callbacks that run through the lifecycle of a GraphQL operation. They can be synchronous or asynchronous and can interact with the operation in several ways:

    • Modify Request Options: Use opContext to change url, headers, or body (similar to RequestInit).
    • Resolve Results: Use useResult to provide a response, either allowing other plugins to continue (non-terminating) or stopping the pipeline (terminating).
    • Post-Query Logic: Use afterQuery to run logic after the operation is finished, such as updating a cache.
    • Access Operation Metadata: Use the operation object to inspect the query, variables, cache policy, or operation type.

    Plugin Context Interface

    A ClientPlugin receives a context object with the following properties:

    PropertyTypeDescription
    useResult(result, terminate?) => voidSignals that the plugin found a result for the operation.
    afterQuery(cb, ctx) => voidRegisters a callback to run after the query is finished.
    operationobjectContains query, variables, cachePolicy, key, and type.
    opContextFetchOptionsContains headers, body, and url (extends RequestInit).
    responseParsedResponseThe actual fetch response containing a parsed body.

    TypeScript Support

    To get automatic typing for the context object, use the definePlugin helper.

    import { definePlugin } from 'villus';
    
    // opContext will be automatically typed
    const myPlugin = definePlugin(({ opContext }) => {
      opContext.headers.Authorization = 'Bearer <token>';
    });
  8. Configure Caching Policies

    main

    Villus caches queries in memory based on the query name, body, and variables. The cache is cleared when the page is refreshed or closed. You can control how queries interact with the cache using cachePolicy at three different levels:

    1. Client Level: Set a global default for all queries using useClient.
    2. Query Level: Set a specific policy for a single useQuery call by passing the extended options object.
    3. Execution Level: Set a policy for a single manual execution by passing it to the execute function.

    Available policies:

    • cache-first: Returns from cache if available; otherwise fetches from network.
    • network-only: Always fetches from network; does not cache.
    • cache-and-network: Returns from cache immediately, then fetches fresh data from network and updates reactively.
    • cache-only: Returns from cache; if not found, returns null for both data and errors.
    // 1. Client level
    useClient({
      url: '/graphql',
      cachePolicy: 'network-only',
    });
    
    // 2. Query level
    const { data } = useQuery({
      query: GetPosts,
      cachePolicy: 'network-only',
    });
    
    // 3. Execution level
    const { execute } = useQuery({ query: GetPosts });
    function run() {
      execute({ cachePolicy: 'network-only' });
    }
  9. How to use multiple GraphQL endpoints in one application

    main

    Villus supports multiple providers. You can query different GraphQL APIs within the same application by creating separate parent components for each client. Each parent component uses useClient with a different URL, effectively scoping that client to its own subtree of components.

    <script setup>
    // ComponentA
    useClient({
      url: '{GITHUB_API_ENDPOINT}',
    });
    </script>
    
    <script setup>
    // ComponentB
    useClient({
      url: '{MY_API}',
    });
    </script>
  10. Map subscription data with useSubscription

    main

    If you want data to represent a specific part of the response rather than the whole object, pass a mapping function as the second argument. This function receives the new result as the first argument.

    Note: When mapping, the returned value becomes the new data. The function can return any type (e.g., a specific field or a boolean).

    <script setup>
    import { useSubscription } from 'villus';
    
    const LastMessage = `
      subscription LastMessage {
        lastMessage {
          id
          from
          message
        }
      }
    `;
    
    const { data: lastMessage } = useSubscription(
      {
        query: LastMessage,
      },
      ({ data }) => {
        // remember that data can be null
        return data?.lastMessage;
      },
    );
    </script>
  11. How the Cache Plugin works

    main

    The Cache Plugin is an in-memory cache that stores query results. It clears automatically when the page reloads or the client is destroyed. Note that the plugin only applies caching logic to queries; mutations always require a fresh response from the server.

    The plugin supports four cache policies:

    • cache-first: Returns cached data if available; otherwise, fetches from the network.
    • network-only: Always fetches from the network and does not store the result in the cache.
    • cache-and-network: Returns cached data immediately (if available), then fetches fresh data from the network to update the reactive state and the cache.
    • cache-only: Returns cached data if available; otherwise, returns an empty response without errors.