From 3afba3c75d24c7ccc5c820a284d7fb5f774d5fd8 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 6 Aug 2024 10:45:53 +0200 Subject: [PATCH] docs, blogs, and so on --- ...024-07-28-rescript-relay-3.0.0-released.md | 299 ++++++++++++++++++ .../docs/making-queries.md | 12 + .../docs/migrating-to-v3.md | 24 +- .../docs/pagination.md | 12 + .../docs/relay-video-series.md | 109 +++++++ .../docs/using-fragments.md | 12 + rescript-relay-documentation/sidebars.js | 1 + 7 files changed, 468 insertions(+), 1 deletion(-) create mode 100755 rescript-relay-documentation/blog/2024-07-28-rescript-relay-3.0.0-released.md create mode 100644 rescript-relay-documentation/docs/relay-video-series.md diff --git a/rescript-relay-documentation/blog/2024-07-28-rescript-relay-3.0.0-released.md b/rescript-relay-documentation/blog/2024-07-28-rescript-relay-3.0.0-released.md new file mode 100755 index 00000000..c878a1b9 --- /dev/null +++ b/rescript-relay-documentation/blog/2024-07-28-rescript-relay-3.0.0-released.md @@ -0,0 +1,299 @@ +--- +id: rescript-relay-3.0.0-released +title: RescriptRelay 3.0.0 released +author: Gabriel Nordeborn +authorTitle: Maintainer of RescriptRelay +authorURL: https://github.com/zth +authorImageURL: https://github.com/zth.png +authorTwitter: ___zth___ +tags: ["releases"] +--- + +It's our great pleasure to announce the release of RescriptRelay 3.0.0. Version 3 is close to a rewrite, leveraging new and shiny features from both ReScript and Relay, creating the best and most idiomatic version of RescriptRelay yet. + +In this post, we're going to talk about the new version and some of its features. But, let's start with a brief history of RescriptRelay, where we're at now, and where we're going. + +## A brief history of RescriptRelay + +RescriptRelay started out as the marriage between my two favorite technologies - ReScript and Relay. + +I've been using Relay virtually since it came out. I'm still in love with it, and it gets better every day. To me, Relay is a proven way to build scalable, maintainable and performant apps in a way that is both fast and robust. + +Similarily, ReScript is an equally large passion for me, and I love it for the same reasons I love Relay - it's a robust, fast, proven way to build scalable, maintainable and performant apps. + +Naturally, marrying these two should be a good idea, right? Well, that's what I set out to do, and after countless hours (5 years and counting), I can say that with version 3 it's as good as ever. + +### Relay is still a great bet to take + +Quite a lot of time has passed since Relay and GraphQL was released to open source. And I strongly believe using it is still a great choice to make. In fact, Relay is still unique in that it addresses a lot of issues that not even recent innovations like React Server Components can address in a good way. + +Meta also still works on it very actively, with the recent expansion of capabilites around local data and using Relay as your general state manager is a testament to. So, Relay continues to be a great bet. It's a proven technology with well know pros/cons, that's here to stay. + +As for RescriptRelay, it has also been around for long and it's as actively developed as ever. We track new features from Relay, and move to new Relay versions as soon as they're released. + +RescriptRelay is in production in quite a lot of companies, and I dare say the general experience is great! People enjoy working with it, and continue chosing it for new enedevours. For this I'm both grateful and excited. + +## A dedicated router for RescriptRelay + +In tandem with RescriptRelay, we've built [RescriptRelayRouter](https://github.com/zth/rescript-relay-router/blob/main/packages/rescript-relay-router/README.md), a web router (React Native coming soon?) built specifically for use with RescriptRelay. It's performant, fully type safe (including for URL search params), and has a bunch of great features and tooling. + +Check it out! + +## A Relay video series + +Together with the release of v3, we've started recording a comprehensive video series on how to build great apps with ReScript + Relay (and RescriptRelayRouter). [Check it out here](/docs/relay-video-series). It's intended to serve as _onboarding material_ for developers new to RescriptRelay. + +This is of course extra important when introducing RescriptRelay at your company, since it ensures you'll have a set path to get new developers productive with ReScript and Relay. + +More videos are continuously being recorded and the goal is to cover all aspects of ReScript and Relay, including the more advanced techniques that exist. + +## A few of the new features + +That's enough background, let's look at some of the new features! + +The lift from 1.0/2.0 to 3.0 has allowed us to enable a number of new very nice features from Relay in RescriptRelay, plus build some more unique features of our own. Version 3 is more robust, smoother, and leverages a bunch of new powerful features from ReScript v11+ that lets you write more concise and better Relay apps as well. + +Below we'll take you on a tour of some of the new features. + +### Input unions (RescriptRelay exclusive) + +GraphQL maps quite well to ReScript, which is a big part in why ReScript and Relay works so well together. However, there are plenty of places still where you'll miss the power of ReScript's type system in GraphQL. + +One of these things is input objects. For output types in GraphQL we have unions, which map well to variants in ReScript. However, GraphQL doesn't have unions for _inputs_. This can needlessly complicate APIs, because there's no good way to communicate that a field or mutation takes _one of_ a set of inputs. + +Using the [`@oneOf` input object and fields RFC](https://github.com/graphql/graphql-spec/pull/825) in GraphQL, we've been able to work around this in RescriptRelay! Any time your server schema defines an input object with the `@oneOf` directive, RescriptRelay will give you a variant to use for that input instead of a regular object. + +Here's an example: + +```graphql +input Address { + streetAddress: String! + postalCode: String! + city: String! +} + +input Coordinates { + lat: Float! + lng: Float! +} + +input Location @oneOf { + byAddress: Address + byCoordinates: Coordinates + byId: ID +} + +type Query { + allShops(location: Location!): ShopConnection +} +``` + +This will produce the following variant for `location`: + +```rescript +type input_ByAddress = { + city: string, +} + +type input_ByLoc = { + lat: float, +} + +type input_Location = +| ByAddress(input_ByAddress) +| ByLoc(input_ByLoc) +| ById(string) +``` + +Which in turn will let you interact with the input like this: + +```rescript +@react.component +let make = (~lat, ~lng) => { + let data = Query.use(~variables={location: ByCoordinates({lat, lng})}) +} +``` + +This can make a world of difference for how easy to use and understandable an API is, and we're really happy this has landed in RescriptRelay. Read more in the [docs on input unions](docs/input-unions). + +### Updatable queries and fragments + +[Updatable queries and fragments](https://relay.dev/docs/guided-tour/updating-data/typesafe-updaters-faq/#what-is-an-updatable-query-or-fragment) is Relay's new way of doing type safe, local updates to the cache. You'll use these in primarily 2 cases: + +- When working with local state managed by Relay (more on this below) +- When updating the local cache after mutations + +Previously, this has been quite complicated, since no official (and type safe) Relay API has existed. That's however fixed now! + +Here's a basic example of an updatable query that lets you update a field in a type safe way: + +```rescript +// ViewerCurrentActiveUpdater.res +module Query = %relay(` + query ViewerCurrentlyActiveUpdaterQuery @updatable { + loggedInUser { + currentlyActive + } + } +`) + +let updateCurrentlyActive = (currentlyActive: bool, ~environment: RescriptRelay.Environment.t) => { + RescriptRelay.commitLocalUpdate(~environment, ~updater=store => { + let {updatableData} = Query.readUpdatableQuery(store) + + updatableData.loggedInUser.currentlyActive = currentlyActive + }) +} +``` + +[Read more in the docs on updatable queries and fragments](/docs/interacting-with-the-store#updatable-fragments). + +### Using Relay as your state manager with Relay resolvers and client schema extensions + +With 3.0, we can finally officially recommend using Relay as your local state manager. We now support all relevant parts from Relay (which one notable exception in `@assignable` fragments, which will be supported soon). + +Turns out, Relay is really powerful as a local state manager, because: + +- It's performant by default, with granular re-renders +- It lets you twine together your local data with your server data +- It even lets you link to server data _from_ local data, so you can create your own local "subgraphs" that actually fetch data from the server +- It's all type safe, and for reading data you work with it just like with server data. No need to consider that it's really local data + +This is very exciting, and will let many Relay apps get rid of other state managers like Redux, Recoil, Jotai etc entirely. Read more in the [docs on interacting with the store](/docs/interacting-with-the-store). + +### Better codesplitting with @preloadable + +The [`@preloadable`](https://relay.dev/docs/glossary/#preloadable) directive in Relay allows you to speed up and parallelize loading of data and component code even more by ensuring that the bare minimum to initiate the query for data is available separately so that it doesn't need to be bundled together with the code for also writing that response into the local data store. + +RescriptRelayRouter already helps you separate loading data and code efficiently to eliminate waterfalls and ensure your network performance is efficient by default. `@preloadable` is another tool in the network performance toolbox, especially efficient for large queries. + +Read more in the [docs on `@preloadable` in RescriptRelay](docs/making-queries#the-preloadable-directive-available-in-v3). + +### Easy and efficient data-driven codesplitting with @codesplit (RescriptRelay exclusive feature) + +With RescriptRelayRouter and preloadable queries, codesplitting is very easy and efficient. But this is primarily at the _route level_. Sometimes you want to codesplit driven by what _data_ is returned, not what route you're on. + +Imagine a blog post where the post content itself can be either plain text or in markdown. When we render markdown, we'll need to load a potentially heavy markdown parser and renderer. But, we don't want to load that unless the blog post content is actually markdown. Enter the `@codesplit` directive! + +The `@codesplit` directive let's you mark fragment spreads to have their components codesplit automatically, and the code for the codesplit component downloaded as soon as possible as the server response with the component data comes back, if that component indeed matches. + +An example: + +```rescript +module Query = %relay(` + query BlogPostView($id: ID!) { + blogPost(id: $id) { + title + content { + ... on Markdown { +// color2 + ...BlogPostMarkdownRenderer_content @alias +// change-line + ...BlogPostMarkdownRenderer_content @alias @codesplit + } + ... on PlainText { + text + } + } + } + } +`) + +@react.component +let make = (~blogPostId) => { + let data = Query.use(~variables={id: blogPostId}) + + switch data.blogPost { + | Some({title, content}) => +// change-line + open Query.CodesplitComponents + +
+ {React.string(title)} + {switch content { + | Some(Markdown({blogPostMarkdownRenderer_content})) => + + | Some(PlainText({text})) =>
{React.string(text)}
+ | None => React.null + }} +
+ | None => + } +} +``` + +That's all it takes! `` is now codesplit, and the code for it will be downloaded if it matches as soon as the server response comes back, not when the codesplit component is first rendered, like with vanilla `React.lazy`. + +Check out the [`@codesplit` documentation](docs/codesplit-directive) for more information and how to start using it. + +> Another good example is something like Facebook's news feed, where there are potentially hundreds of different components that might be needed depending on what type of news feed items are returned from the server. You want to codesplit all of these so you only load code to render the actual stories you get back, but you won't know what components to load until you get the actual server response back. `@codesplit` helps you do this easily and with great performance. + +### @alias and conditional fragments + +Relay uses the fragment model, which is one of the most powerful things about GraphQL. However, it has traditionally been really difficult to figure out if a fragment was actually fetched or not. + +With the [`@alias`](docs/using-fragments#conditional-fragments-and-more-with-the-alias-directive) directive, this has now become possible, and easy! An example: + +```rescript +module Query = %relay(` + query BlogPostView($id: ID!) { + blogPost(id: $id) { +// color2 + ...BlogPostTitle_post +// change-line + ...BlogPostTitle_post @alias + } + } +`) + +@react.component +let make = (~blogPostId) => { + let data = Query.use(~variables={id: blogPostId}) + + switch data.blogPost { +// color2 + | Some({fragmentRefs}) => +// change-line + | Some({blogPostTitle_post}) => + | None => + } +} +``` + +Relay puts the fragment ref on its own prop here. This is especially important when including that fragment is conditional: + +```rescript +module Query = %relay(` + query BlogPostView($id: ID!, $includeTitle: Boolean!) { + blogPost(id: $id) { + ...BlogPostTitle_post @alias @include(if: $includeTitle) + } + } +`) + +@react.component +let make = (~blogPostId, ~includeTitle) => { + let data = Query.use(~variables={id: blogPostId, includeTitle}) + + switch data.blogPost { + | Some({blogPostTitle_post: Some(blogPostTitle_post)}) => + // With the regular `fragmentRefs` approach where all fragment refs are on the same prop, + // there's no way to figure out if `BlogPostTitle_post` was actually included in the + // response without resorting to hacks. + + | _ => + } +} +``` + +This makes working with conditional fragments easier and safer. + +## Going from V2 to V3 + +Since V3 has a lot of changes, you'll need to take some manual steps to migrate from prior versions to V3. Check out the [migration doc](docs/migrating-to-v3) for more information. + +## Wrapping up + +Thank you for reading, and we hope you're as excited as we are for RescriptRelay v3! + +Oh, and also, if you haven't already, you should check out the [tutorial on RescriptRelay](docs/tutorial/tutorial-intro). And of course, the new [Relay video series](/docs/relay-video-series). diff --git a/rescript-relay-documentation/docs/making-queries.md b/rescript-relay-documentation/docs/making-queries.md index b996cb59..bf03349b 100644 --- a/rescript-relay-documentation/docs/making-queries.md +++ b/rescript-relay-documentation/docs/making-queries.md @@ -10,6 +10,18 @@ sidebar_label: Making Queries - [A Guided Tour of Relay: Queries](https://relay.dev/docs/guided-tour/rendering/queries) - [React documentation: Suspense for Data Fetching](https://reactjs.org/docs/concurrent-mode-suspense.html) +Videos from the Relay video series covering queries: + + + ## Making Queries Let's make our first query! diff --git a/rescript-relay-documentation/docs/migrating-to-v3.md b/rescript-relay-documentation/docs/migrating-to-v3.md index 092aeaea..35838aab 100644 --- a/rescript-relay-documentation/docs/migrating-to-v3.md +++ b/rescript-relay-documentation/docs/migrating-to-v3.md @@ -249,7 +249,29 @@ In addition to this you might occasionally need to explicitly pattern match the We're almost there! Now we can upgrade to an actual `alpha` version of RescriptRelay, and upgrade Relay to v16: ```bash -yarn install rescript-relay@3.0.0-alpha.5 relay-runtime@latest react-relay@latest && +yarn install rescript-relay@3.0.0 relay-runtime@17 react-relay@17 +``` + +If you have custom scalars set up and mapped, you'll need to change the `customScalars` prop name to `customScalarTypes` in your `relay.config.js`: + +```js title="relay.config.js" +module.exports = { + src: "./src", + schema: "./schema.graphql", + artifactDirectory: "./src/__generated__", +// color2 + customScalars: { +// change-line + customScalarTypes: { + Datetime: "string", + Color: "Color.t", + }, +}; +``` + +Now you should be able to build: + +```bash yarn rescript-relay-compiler && yarn rescript build ``` diff --git a/rescript-relay-documentation/docs/pagination.md b/rescript-relay-documentation/docs/pagination.md index c8f42a55..75a64b95 100644 --- a/rescript-relay-documentation/docs/pagination.md +++ b/rescript-relay-documentation/docs/pagination.md @@ -11,6 +11,18 @@ sidebar_label: Pagination - [The Relay server specification: Connections](https://relay.dev/docs/en/graphql-server-specification.html#connections) - [React documentation: Suspense for Data Fetching](https://reactjs.org/docs/concurrent-mode-suspense.html) +Videos from the Relay video series covering pagination: + + + ## Pagination in Relay > The features outlined on this page requires that your schema follow the [Relay specification](https://relay.dev/docs/guides/graphql-server-specification). Read more about using RescriptRelay with schemas that don't conform to the Relay specification [here](using-with-schemas-that-dont-conform-to-the-relay-spec). diff --git a/rescript-relay-documentation/docs/relay-video-series.md b/rescript-relay-documentation/docs/relay-video-series.md new file mode 100644 index 00000000..733182e7 --- /dev/null +++ b/rescript-relay-documentation/docs/relay-video-series.md @@ -0,0 +1,109 @@ +--- +id: relay-video-series +title: Relay Video Series +sidebar_label: Relay Video Series +--- + +We've got a video series covering Relay, some GraphQL, ReScript and RescriptRelayRouter. It's growing and will eventually cover everything you need to get up and running using these techniques. + +This series is intended to function as _onboarding material_ for developers starting with Relay and ReScript. + +Even if you're not using RescriptRelay (yet, right!) there's a good amount of Relay knowledge and tips and tricks in there, so check it out. + +This page lists all videos and what they cover. + +## Introduction and project outline + +- Setting up a new RescriptRelay project +- Setting up your editor +- Basic route configuration with RescriptRelayRouter +- The Relay network layer + +...and more. + + + +## Making lazy and preloaded Relay queries + +- Making lazy queries +- Using custom scalars with custom types +- Autoconverting custom scalars to ReScript +- Understanding network waterfalls and what you can do about them +- Making preloaded queries +- Render-as-you-fetch, preloading code and data in parallel + + + +## Reusable components with GraphQL fragments, and routing + +- The Node interface and why I use it a lot +- Using GraphQL fragments to create composable and reusable UI components +- Creating new routes with RescriptRelayRouter +- Type safe links with RescriptRelayRouter +- Controlling how data and code is loaded for each link + + + +## Relay, partial rendering, and suspense + +- The Node interface +- When and why Relay suspends +- How to control loading states and route transitions using suspense and the RescriptRelayRouter +- Partial rendering of views with existing cached data +- Using the Relay browser dev tools +- Using the React browser dev tools to work with suspense + + + +## Pagination in Relay with connections + +- Setting up pagination for a fragment in Relay +- The `@refetchable` Relay directive and how Relay optimizes your pagination queries +- The `@argumentDefinitions` Relay directive +- The `@connection` Relay directive +- The `@connection` Relay directive `filters` argument and how that works +- Why connections are structured the way they are +- How to paginate with Relay +- Loading states when paginating + + diff --git a/rescript-relay-documentation/docs/using-fragments.md b/rescript-relay-documentation/docs/using-fragments.md index 0ebf7cd2..dfb94a0b 100644 --- a/rescript-relay-documentation/docs/using-fragments.md +++ b/rescript-relay-documentation/docs/using-fragments.md @@ -9,6 +9,18 @@ sidebar_label: Using Fragments - [Fragments in GraphQL](https://graphql.org/learn/queries/#fragments) - [A Guided Tour of Relay: Fragments](https://relay.dev/docs/guided-tour/rendering/fragments) +Videos from the Relay video series covering fragments: + + + ## Using Fragments One of the main things that make Relay so powerful is using _GraphQL fragments_ to co-locate the data-demands of your components with your actual component code. This leads to well-isolated components that are very portable and easy to maintain. diff --git a/rescript-relay-documentation/sidebars.js b/rescript-relay-documentation/sidebars.js index a4822938..27f2e281 100755 --- a/rescript-relay-documentation/sidebars.js +++ b/rescript-relay-documentation/sidebars.js @@ -45,6 +45,7 @@ module.exports = { ], "API Reference": ["api-reference", "relay-environment"], Guides: [ + "relay-video-series", "codebase-health-considerations", "editor-support-and-development-environment", "custom-scalars",