Migrating to Relay Modern

May. 25, 2017

Introduction

With the release of Relay Modern comes a new way to create Containers and write fragments. Luckily you do not need to rewrite your entire application to take advantage of these updates. There is a compatibility mode that lets Classic and Modern components run at the same time. There is even an official Conversion Playbook to help walk you through the steps needed to update your app. However, while we were converting our app we noticed that sometimes the Playbook hides important information behind links. After getting stuck a few times we decided to write down what it took to get everything up and running.

Step 0: Incrementally convert to Relay Compat

The first steps invole updating the react-relay library and setting up new build tools to get ready for the conversion to Relay Modern syntax.

yarn add react-relay

react-relay -> react-relay/classic

After the upgrade react-relay will point to modern by default so update all imports to point to react-relay/classic instead.

It should be as simple as using an editor to find and replace all instances of react-relay with react-relay/classic but there are also codemods that might be able to automate this step.

yarn add --dev babel-plugin-relay

Since we are upgrading from Relay Classic to Relay Modern/Compat we will need to remember to add "compat": true and "schema": "schema/schema.graphql" flags to the babel config.

The schema file from Relay Classic can be in either .graphql or .json format.

// .babelrc
{
 "presets": [...],
 "plugins": [..., ["relay", {"compat": true, "schema": "schema/schema.json"}]]
}

Modern components need to use new relay compiler even in react-relay/compat mode.

yarn add --dev relay-compiler

Note that the relay-compiler requires that you have watchman globally installed even if you are not trying to run it in --watch mode. You should install it before continuing.

Point the new relay-compiler to the same schema.graphql used in the babel plugin - again this schema can be in either .json or .graphql format.

// package.json
"scripts": {
  "relay": "relay-compiler --src ./src --schema ./schema/schema.json"
}

Now run the compiler - it should not find anything yet:

❯ yarn run relay
yarn run v0.17.9
$ relay-compiler --src ./src --schema ./schema/schema.json
HINT: pass --watch to keep watching for changes.
Parsed default in 0.08s

Writing default
Writer time: 0.12s [0.12s compiling, 0.00s generating, 0.00s extra]
Unchanged: 0 files
Written default in 0.30s
✨  Done in 1.01s.

Checkpoint!

  • All components using react-relay/classic
  • Still using Relay.createContainer
  • Still using Relay.QL
  • relay-compiler runs but does not find any queries
  • Application works as before

Step 1: Incrementally convert to Relay Compat!

Start using the modern syntax and compiler for some containers while keeping compatibility with the rest of the project. It might be easier to start with a simple container that does not have fragments in its query but there is also a codemod that could automate this step.

react-relay/classic -> react-relay/compat

Use react-relay/compat instead of react-relay because compat components use Modern syntax while still remaining compatible with Classic containers.

Update the containers by using createFragmentContainer in place of Relay.createContainer and the fragments by using graphql instead of Relay.QL. ${MyComponent.getFragment('hits')} is gone and replaced with more standard graphql syntax ...MyComponent_hits.

Notes on Fragments

  • Fragments need a name
  • Name needs to start with module name
  • Fragment key can be embedded in fragment name
// MyComponent.js
-import Relay from 'react-relay/classic';
+import {
+  createFragmentContainer,
+  graphql,
+} from 'react-relay/compat';

...

-export default Relay.createContainer(
+export default createFragmentContainer(
   MyComponent,
- {
-   fragments: {
-     viewer: () => Relay.QL`
-       fragment on Root {
-         projects {
-           ${TableData.getFragment('hits')}
-         }
-       }`
-   }
- }
+ graphql`
+   fragment MyComponent_viewer on Root {
+      projects {
+        ...TableData_hits
+      }
+   }
+ `
)

Now run the relay-compiler again but this time it should find the new graphql queries.

❯ yarn run relay
yarn run v0.17.9
$ relay-compiler --src ./src --schema ./schema/schema.json
HINT: pass --watch to keep watching for changes.
Parsed default in 0.11s

Writing default
Writer time: 0.32s [0.11s compiling, 0.21s generating, 0.00s extra]
Created:
 - MyComponent_viewer.graphql.js
Unchanged: 0 files
Written default in 0.49s

Checkpoint!

  • At least one component uses react-relay/compat
  • Now using createFragmentContainer
  • Query fragment now uses graphql
  • relay-compiler runs and finds the new queries
  • Application works as before

Next Steps

From here it is a matter of moving over the rest of the Classic containers to the Modern API. That is still a work in progress for us but we will have a new guide out when we are finished.

Shane Wilson, Team Lead
Software Architect with a passion for making tools that make developers' lives easier. Functional Programming geek. Facebook OSS fanboy (React, Relay, ReasonML).