06

The compiler does the work before your app runs

relay-compiler reads every graphql tag in the project, validates it against schema.graphql, and writes an artifact per fragment and operation: a precomputed runtime AST, TypeScript types, and (here) a persisted query id. Pick any artifact this app generated.
Kind
query
Artifact size
9.9 KB
Operation text
494 B
What the browser sends
45 B + vars

1 · You write

src/components/network/WaterfallDemo.tsx
query WaterfallDemoQuery($username: String!) {
  user(username: $username) {
    name
    avatarColor
    posts(first: 4) {
      edges {
        node {
          id
          title
          comments(first: 5) {
            edges {
              node {
                id
                body
                author {
                  name
                  avatarColor
                }
              }
            }
          }
        }
      }
    }
  }
}

2 · Types you import

WaterfallDemoQuery.graphql.ts
export type WaterfallDemoQuery$variables = {
  username: string;
};
export type WaterfallDemoQuery$data = {
  readonly user: {
    readonly avatarColor: string;
    readonly name: string;
    readonly posts: {
      readonly edges: ReadonlyArray<{
        readonly node: {
          readonly comments: {
            readonly edges: ReadonlyArray<{
              readonly node: {
                readonly author: {
                  readonly avatarColor: string;
                  readonly name: string;
                };
                readonly body: string;
                readonly id: string;
              } | null | undefined;
            } | null | undefined> | null | undefined;
          };
          readonly id: string;
          readonly title: string;
        } | null | undefined;
      } | null | undefined> | null | undefined;
    };
  } | null | undefined;
};
export type WaterfallDemoQuery = {
  response: WaterfallDemoQuery$data;
  variables: WaterfallDemoQuery$variables;
};

3 · Operation text, persisted at build time

md5 8c24ab54b1e6a5c988b448362bef8421

Fragments from every component are inlined into one document. It lives in persisted_queries.json on the server; the client only knows the hash.

query WaterfallDemoQuery(
  $username: String!
) {
  user(username: $username) {
    name
    avatarColor
    posts(first: 4) {
      edges {
        node {
          id
          title
          comments(first: 5) {
            edges {
              node {
                id
                body
                author {
                  name
                  avatarColor
                  id
                }
              }
            }
          }
        }
      }
    }
    id
  }
}

4 · Runtime artifact

imported in place of the graphql`` tag

A preprocessed AST, so there's no GraphQL parsing in the browser. The reader part tells useFragment what to read; the normalization part tells the store how to write.

/**
 * @generated SignedSource<<6233e45d241132096dfb54655d67a775>>
 * @relayHash 8c24ab54b1e6a5c988b448362bef8421
 * @lightSyntaxTransform
 */

/* tslint:disable */
/* eslint-disable */
// @ts-nocheck

// @relayRequestID 8c24ab54b1e6a5c988b448362bef8421

import { ConcreteRequest } from 'relay-runtime';
export type WaterfallDemoQuery$variables = {
  username: string;
};
export type WaterfallDemoQuery$data = {
  readonly user: {
    readonly avatarColor: string;
    readonly name: string;
    readonly posts: {
      readonly edges: ReadonlyArray<{
        readonly node: {
          readonly comments: {
            readonly edges: ReadonlyArray<{
              readonly node: {
                readonly author: {
                  readonly avatarColor: string;
                  readonly name: string;
                };
                readonly body: string;
                readonly id: string;
              } | null | undefined;
            } | null | undefined> | null | undefined;
          };
          readonly id: string;
          readonly title: string;
        } | null | undefined;
      } | null | undefined> | null | undefined;
    };
  } | null | undefined;
};
export type WaterfallDemoQuery = {
  response: WaterfallDemoQuery$data;
  variables: WaterfallDemoQuery$variables;
};

const node: ConcreteRequest = (function(){
var v0 = [
  {
    "defaultValue": null,
    "kind": "LocalArgument",
    "name": "username"
  }
],
v1 = [
  {
    "kind": "Variable",
    "name": "username",
    "variableName": "username"
  }
],
v2 = {
  "alias": null,
  "args": null,
  "kind": "ScalarField",
  "name": "name",
  "storageKey": null
},
v3 = {
  "alias": null,
  "args": null,
  "kind": "ScalarField",
  "name": "avatarColor",
  "storageKey": null
},
v4 = [
  {
    "kind": "Literal",
    "name": "first",
    "value": 4
  }
],
v5 = {
  "alias": null,
  "args": null,
  "kind": "ScalarField",
  "name": "id",
  "storageKey": null
},
v6 = {
  "alias": null,
  "args": null,
  "kind": "ScalarField",
  "name": "title",
  "storageKey": null
},
v7 = [
  {
    "kind": "Literal",
    "name": "first",
    "value": 5
  }
],
v8 = {
  "alias": null,
  "args": null,
  "kind": "ScalarField",
  "name": "body",
  "storageKey": null
};
return {
  "fragment": {
    "argumentDefinitions": (v0/*:: as any*/),
    "kind": "Fragment",
    "metadata": null,
    "name": "WaterfallDemoQuery",
    "selections": [
      {
        "alias": null,
        "args": (v1/*:: as any*/),
        "concreteType": "User",
        "kind": "LinkedField",
        "name": "user",
        "plural": false,
        "selections": [
          (v2/*:: as any*/),
          (v3/*:: as any*/),
          {
            "alias": null,
            "args": (v4/*:: as any*/),
            "concreteType": "PostConnection",
            "kind": "LinkedField",
            "name": "posts",
            "plural": false,
            "selections": [
              {
                "alias": null,
                "args": null,
                "concreteType": "PostEdge",
                "kind": "LinkedField",
                "name": "edges",
                "plural": true,
                "selections": [
                  {
                    "alias": null,
                    "args": null,
                    "concreteType": "Post",
                    "kind": "LinkedField",
                    "name": "node",
                    "plural": false,
                    "selections": [
                      (v5/*:: as any*/),
                      (v6/*:: as any*/),
                      {
                        "alias": null,
                        "args": (v7/*:: as any*/),
                        "concreteType": "CommentConnection",
                        "kind": "LinkedField",
                        "name": "comments",
                        "plural": false,
                        "selections": [
                          {
                            "alias": null,
                            "args": null,
                            "concreteType": "CommentEdge",
                            "kind": "LinkedField",
                            "name": "edges",
                            "plural": true,
                            "selections": [
                              {
                                "alias": null,
                                "args": null,
                                "concreteType": "Comment",
                                "kind": "LinkedField",
                                "name": "node",
                                "plural": false,
                                "selections": [
                                  (v5/*:: as any*/),
                                  (v8/*:: as any*/),
                                  {
                                    "alias": null,
                                    "args": null,
                                    "concreteType": "User",
                                    "kind": "LinkedField",
                                    "name": "author",
                                    "plural": false,
                                    "selections": [
                                      (v2/*:: as any*/),
                                      (v3/*:: as any*/)
                                    ],
                                    "storageKey": null
                                  }
                                ],
                                "storageKey": null
                              }
                            ],
                            "storageKey": null
                          }
                        ],
                        "storageKey": "comments(first:5)"
                      }
                    ],
                    "storageKey": null
                  }
                ],
                "storageKey": null
              }
            ],
            "storageKey": "posts(first:4)"
          }
        ],
        "storageKey": null
      }
    ],
    "type": "Query",
    "abstractKey": null
  },
  "kind": "Request",
  "operation": {
    "argumentDefinitions": (v0/*:: as any*/),
    "kind": "Operation",
    "name": "WaterfallDemoQuery",
    "selections": [
      {
        "alias": null,
        "args": (v1/*:: as any*/),
        "concreteType": "User",
        "kind": "LinkedField",
        "name": "user",
        "plural": false,
        "selections": [
          (v2/*:: as any*/),
          (v3/*:: as any*/),
          {
            "alias": null,
            "args": (v4/*:: as any*/),
            "concreteType": "PostConnection",
            "kind": "LinkedField",
            "name": "posts",
            "plural": false,
            "selections": [
              {
                "alias": null,
                "args": null,
                "concreteType": "PostEdge",
                "kind": "LinkedField",
                "name": "edges",
                "plural": true,
                "selections": [
                  {
                    "alias": null,
                    "args": null,
                    "concreteType": "Post",
                    "kind": "LinkedField",
                    "name": "node",
                    "plural": false,
                    "selections": [
                      (v5/*:: as any*/),
                      (v6/*:: as any*/),
                      {
                        "alias": null,
                        "args": (v7/*:: as any*/),
                        "concreteType": "CommentConnection",
                        "kind": "LinkedField",
                        "name": "comments",
                        "plural": false,
                        "selections": [
                          {
                            "alias": null,
                            "args": null,
                            "concreteType": "CommentEdge",
                            "kind": "LinkedField",
                            "name": "edges",
                            "plural": true,
                            "selections": [
                              {
                                "alias": null,
                                "args": null,
                                "concreteType": "Comment",
                                "kind": "LinkedField",
                                "name": "node",
                                "plural": false,
                                "selections": [
                                  (v5/*:: as any*/),
                                  (v8/*:: as any*/),
                                  {
                                    "alias": null,
                                    "args": null,
                                    "concreteType": "User",
                                    "kind": "LinkedField",
                                    "name": "author",
                                    "plural": false,
                                    "selections": [
                                      (v2/*:: as any*/),
                                      (v3/*:: as any*/),
                                      (v5/*:: as any*/)
                                    ],
                                    "storageKey": null
                                  }
                                ],
                                "storageKey": null
                              }
                            ],
                            "storageKey": null
                          }
                        ],
                        "storageKey": "comments(first:5)"
                      }
                    ],
                    "storageKey": null
                  }
                ],
                "storageKey": null
              }
            ],
            "storageKey": "posts(first:4)"
          },
          (v5/*:: as any*/)
        ],
        "storageKey": null
      }
    ]
  },
  "params": {
    "id": "8c24ab54b1e6a5c988b448362bef8421",
    "metadata": {},
    "name": "WaterfallDemoQuery",
    "operationKind": "query",
    "text": null
  }
};
})();

(node as any).hash = "7c86fb967abce43c5442365f767f49ea";

export default node;
  • why it mattersA typo in a field name fails the build, not the user's session. Every fragment is checked against the schema on every save.
  • why it mattersTypes come from the fragment rather than the whole schema, so a component's data type has exactly the fields it asked for.
  • why it mattersPersisted queries ship for free: smaller requests, cacheable GETs, and a server that can refuse any query it didn't compile.