Skip to content

Solid Integration

Mearie provides Solid primitives that leverage fine-grained reactivity for optimal performance and full type safety.

Installation

Install the core package and the Solid integration:

sh
npm install mearie @mearie/solid
sh
yarn add mearie @mearie/solid
sh
pnpm add mearie @mearie/solid
sh
bun add mearie @mearie/solid
sh
deno add npm:mearie npm:@mearie/solid

Setup

1. Add Build Plugin

Add Mearie's build plugin to enable automatic type generation from your GraphQL documents:

typescript
// vite.config.ts
import { defineConfig } from 'vite';
import solid from 'vite-plugin-solid';
import mearie from 'mearie/vite';

export default defineConfig({
  plugins: [solid(), mearie()],
});

TIP

By default, Mearie looks for ./schema.graphql relative to your vite.config.ts. For custom schema locations or advanced configuration, see Codegen Config.

2. Create Client

Create a GraphQL client with your API endpoint. Links are middleware-style handlers that process requests and responses. At least one terminating link is required (in this case, httpLink). See Links for more details.

typescript
// src/lib/graphql-client.ts
import { createClient, httpLink, cacheLink, dedupLink } from 'mearie';

export const client = createClient({
  links: [
    dedupLink(),
    cacheLink(),
    httpLink({
      url: 'https://api.example.com/graphql',
    }),
  ],
});

3. Set Up Provider

Wrap your app with the client provider to make the GraphQL client available throughout your component tree:

tsx
// src/index.tsx
import { ClientProvider } from '@mearie/solid';
import { client } from './lib/graphql-client';

<ClientProvider client={client}>
  <App />
</ClientProvider>;

Primitives

createQuery

Fetch data with fine-grained reactivity:

tsx
import { type Component } from 'solid-js';
import { graphql } from 'mearie';
import { createQuery } from '@mearie/solid';

interface UserProfileProps {
  userId: string;
}

export const UserProfile: Component<UserProfileProps> = (props) => {
  const query = createQuery(
    graphql(`
      query GetUserQuery($id: ID!) {
        user(id: $id) {
          id
          name
          email
          avatar
          bio
          age
        }
      }
    `),
    () => ({
      id: props.userId,
    }),
  );

  if (query.loading) return <div>Loading...</div>;
  if (query.error) return <div>Error: {query.error.message}</div>;

  return (
    <div>
      <img src={query.data.user.avatar} alt={query.data.user.name} />
      <h1>{query.data.user.name}</h1>
      {query.data.user.bio && <p>{query.data.user.bio}</p>}
      <p>Email: {query.data.user.email}</p>
      <p>Age: {query.data.user.age}</p>
      <button onClick={() => query.refetch()}>Refresh</button>
    </div>
  );
};

createMutation

Modify data with automatic cache updates:

tsx
import { type Component, createSignal } from 'solid-js';
import { graphql } from 'mearie';
import { createMutation } from '@mearie/solid';

interface EditUserFormProps {
  userId: string;
}

export const EditUserForm: Component<EditUserFormProps> = (props) => {
  const [name, setName] = createSignal('');
  const mutation = createMutation(
    graphql(`
      mutation UpdateUserMutation($id: ID!, $name: String!) {
        updateUser(id: $id, input: { name: $name }) {
          id
          name
        }
      }
    `),
  );

  const handleSubmit = async (e: SubmitEvent) => {
    e.preventDefault();
    await mutation.mutate({ id: props.userId, name: name() });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input value={name()} onInput={(e) => setName(e.currentTarget.value)} required />
      <button type="submit" disabled={mutation.loading}>
        {mutation.loading ? 'Saving...' : 'Save'}
      </button>
    </form>
  );
};

createFragment

Co-locate data requirements with components:

tsx
import { type Component } from 'solid-js';
import { graphql } from 'mearie';
import { createFragment } from '@mearie/solid';
import type { UserCard_user$key } from 'mearie/types';

interface UserCardProps {
  user: UserCard_user$key;
}

export const UserCard: Component<UserCardProps> = (props) => {
  const data = createFragment(
    graphql(`
      fragment UserCard_user on User {
        id
        name
        avatar
        email
      }
    `),
    () => props.user,
  );

  return (
    <div class="card">
      <img src={data().avatar} alt={data().name} />
      <h3>{data().name}</h3>
      <p>{data().email}</p>
    </div>
  );
};

createSubscription

Real-time updates via subscriptions:

tsx
import { type Component } from 'solid-js';
import { graphql } from 'mearie';
import { createSubscription } from '@mearie/solid';

interface ChatMessagesProps {
  chatId: string;
}

export const ChatMessages: Component<ChatMessagesProps> = (props) => {
  const subscription = createSubscription(
    graphql(`
      subscription MessageAddedSubscription($chatId: ID!) {
        messageAdded(chatId: $chatId) {
          id
          body
          author {
            name
          }
        }
      }
    `),
    () => ({ chatId: props.chatId }),
  );

  return (
    <div>
      <div>{subscription.loading ? 'Connecting...' : 'Connected'}</div>
      {subscription.data?.messageAdded && (
        <div>
          <strong>{subscription.data.messageAdded.author.name}:</strong>
          {subscription.data.messageAdded.body}
        </div>
      )}
    </div>
  );
};

Fine-Grained Reactivity

Solid's fine-grained reactivity works seamlessly with Mearie:

tsx
import { type Component } from 'solid-js';
import { graphql } from 'mearie';
import { createQuery } from '@mearie/solid';

interface UserProfileProps {
  userId: string;
}

export const UserProfile: Component<UserProfileProps> = (props) => {
  const query = createQuery(
    graphql(`
      query GetUserQuery($id: ID!) {
        user(id: $id) {
          id
          name
          email
        }
      }
    `),
    () => ({
      id: props.userId,
    }),
  );

  return (
    <div>
      <h1>{query.data.user.name}</h1>
      <p>{query.data.user.email}</p>
    </div>
  );
};

Next Steps