Skip to content

Commit

Permalink
Add Relay client configuration to web (#260)
Browse files Browse the repository at this point in the history
  • Loading branch information
koistya committed Sep 19, 2020
1 parent 329f05b commit b3e9321
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 7 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,6 @@ module.exports = {
"/**/node_modules",
"/coverage",
"/dist/",
"/web/out/",
],
};
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Compiled output
/*/.next/
/dist/
/web/out/

# Dependencies
node_modules/
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/*/.next/
/.cache/
/dist/
/web/out/

# Yarn
.yarn/cache
Expand Down
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ module.exports = {
"<rootDir>/db/",
"<rootDir>/dist/",
"<rootDir>/scripts/",
"<rootDir>/web/out/",
],
};
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
"exclude": [
".cache/**/*",
".yarn/**/*",
"*/.next/**/*",
"dist/**/*",
"*/.next/**/*"
"web/out/**/*"
]
}
3 changes: 2 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"next": "^9.5.3",
"react": "^17.0.0-rc.1",
"react-dom": "^17.0.0-rc.1",
"react-relay": "0.0.0-experimental-183bdd28"
"react-relay": "0.0.0-experimental-183bdd28",
"relay-runtime": "^10.0.1"
},
"devDependencies": {
"@emotion/babel-plugin": "^11.0.0-next.17",
Expand Down
16 changes: 12 additions & 4 deletions web/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,25 @@
*/

import React from "react";
import { CacheProvider } from "@emotion/react";
import { cache } from "@emotion/css";
import { CacheProvider } from "@emotion/react";
import { RelayEnvironmentProvider } from "react-relay/hooks";
import type { AppProps } from "next/app";

import { createRelay } from "../relay";

function App(props: AppProps): JSX.Element {
const { Component, pageProps } = props;

// It should be possible to reset Relay environment by calling setRelay(...)
const [relay] = React.useState(createRelay);

return (
<CacheProvider value={cache}>
<Component {...pageProps} />
</CacheProvider>
<RelayEnvironmentProvider environment={relay}>
<CacheProvider value={cache}>
<Component {...pageProps} />
</CacheProvider>
</RelayEnvironmentProvider>
);
}

Expand Down
58 changes: 58 additions & 0 deletions web/relay/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Relay Client Configuration

[Relay](https://relay.dev/) client configurations for both (Node.js) server and
browser environments.

The main difference between these two is the network layer as you can see below:

##### [`package.json`](./package.json)

```json
{
"main": "relay.server.ts",
"browser": "relay.browser.ts"
}
```

##### [`relay.browser.ts`](./relay.browser.ts)

```ts
fetch("/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
body: {
query: operation.text,
variables,
},
});
```

##### [`relay.server.ts`](./relay.server.ts)

```ts
import { graphql } from "graphql";
import { schema, Context } from "@example/api";
```

```ts
graphql({
schema,
source: operation.text,
contextValue: new Context(req),
variableValues: variables,
operationName: operation.name,
});
```

Note that implementing server-side version of Relay client is not strictly
necessary. As longs as the app renders fast enough (using optimization
techniques other than full SSR) and meta tags are in place (`<title>...</title>`,
`<meta name="description" content="...">`, etc., a.k.a. partial SSR) it should
be good enough in most cases.

## References

- [Relay hooks, a step by step guide](https://relay.dev/docs/en/experimental/step-by-step)
6 changes: 6 additions & 0 deletions web/relay/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "relay",
"private": true,
"browser": "relay.browser.ts",
"main": "relay.server.ts"
}
75 changes: 75 additions & 0 deletions web/relay/relay.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Relay configuration for the browser environment.
*
* @ee https://relay.dev/docs/en/a-guided-tour-of-relay
* @see https://relay.dev/docs/en/network-layer
* @copyright 2016-present Kriasoft (https://git.io/vMINh)
*/

import {
Environment,
Network,
QueryResponseCache,
RecordSource,
Store,
} from "relay-runtime";
import type { GraphQLResponseWithData } from "relay-runtime";

if (!process.browser) {
throw new Error("Not supported. See package.json->browser field.");
}

const oneMinute = 60 * 1000;
const cache = new QueryResponseCache({ size: 250, ttl: oneMinute });

export function createRelay(): Environment {
const source = new RecordSource();
const store = new Store(source);

const network = Network.create((operation, variables, cacheConfig) => {
const queryID = operation.text;
const isMutation = operation.operationKind === "mutation";
const isQuery = operation.operationKind === "query";
const forceFetch = cacheConfig?.force;

// Try to get data from cache on queries
const fromCache = queryID && cache.get(queryID, variables);
if (isQuery && fromCache !== null && !forceFetch) {
return fromCache as GraphQLResponseWithData;
}

// Otherwise, fetch data from server
return fetch("/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
body: JSON.stringify({
query: operation.text,
variables,
}),
})
.then((res) => {
return res.json();
})
.then((json) => {
// Update cache on queries
if (isQuery && queryID && json) {
cache.set(queryID, variables, json);
}
// Clear cache on mutations
if (isMutation) {
cache.clear();
}

return json;
});
});

return new Environment({
handlerProvider: null,
network,
store,
});
}
27 changes: 27 additions & 0 deletions web/relay/relay.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Relay configuration for the server (Node.js) environment.
*
* @ee https://relay.dev/docs/en/a-guided-tour-of-relay
* @see https://relay.dev/docs/en/network-layer
* @copyright 2016-present Kriasoft (https://git.io/vMINh)
*/

import { Environment, Network, RecordSource, Store } from "relay-runtime";

if (process.browser) {
throw new Error("Not supported. See package.json->browser field.");
}

export function createRelay(): Environment {
const source = new RecordSource();
const store = new Store(source);
const network = Network.create(() => {
throw new Error("Not implemented.");
});

return new Environment({
handlerProvider: null,
network,
store,
});
}
3 changes: 2 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14723,7 +14723,7 @@ fsevents@^1.2.7:
languageName: node
linkType: hard

"relay-runtime@npm:10.0.1":
"relay-runtime@npm:10.0.1, relay-runtime@npm:^10.0.1":
version: 10.0.1
resolution: "relay-runtime@npm:10.0.1"
dependencies:
Expand Down Expand Up @@ -17559,6 +17559,7 @@ typescript@^3.0.0:
relay-compiler: ^10.0.1
relay-compiler-language-typescript: ^13.0.1
relay-config: ^10.0.1
relay-runtime: ^10.0.1
typescript: 4.0.2
languageName: unknown
linkType: soft
Expand Down

0 comments on commit b3e9321

Please sign in to comment.