From 685b38b19d8d4575063d4d67f28c95ecd107585b Mon Sep 17 00:00:00 2001 From: JV Date: Mon, 1 Aug 2022 11:12:42 -0600 Subject: [PATCH 01/12] Roadmap update (#9966) * emptye * roadmap update aug 2022 --- ROADMAP.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 0fe582fa46f..aecdf1125d0 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ # 🔮 Apollo Client Roadmap -**Last updated: June 2022** +**Last updated: Aug 2022** For up to date release notes, refer to the project's [Change Log](https://github.com/apollographql/apollo-client/blob/main/CHANGELOG.md). @@ -15,15 +15,19 @@ For up to date release notes, refer to the project's [Change Log](https://github ## 3.7 -- Release 3.7: will focus on cache & performance improvements as well as adding new hooks: `useBackgroundQuery`, `useFragment` See Github [3.7 Milestone](https://github.com/apollographql/apollo-client/milestone/28) for more details. +- Release 3.7 will focus on adding support for the `@defer` directive. See Github [3.7 Milestone](https://github.com/apollographql/apollo-client/milestone/28) for more details. ## 3.8 -- Release 3.8 will focus on adding support for `Suspense` & `RefetchQuery` improvements. See Github [3.8 Milestone](https://github.com/apollographql/apollo-client/milestone/30) for more details. +- Release 3.8: will focus on cache & performance improvements as well as adding new hooks: `useBackgroundQuery`, `useFragment` See Github [3.8 Milestone](https://github.com/apollographql/apollo-client/milestone/30) for more details. ## 3.9 -- *TBD* +- Release 3.9 will focus on adding support for React 18 `Suspense`. See Github [3.9 Milestone](https://github.com/apollographql/apollo-client/milestone/32) for more details. + +## 3.10 + +- Release 3.10 will focus on adding better support for React 18 `SSR` architecture. See Github [3.10 Milestone](https://github.com/apollographql/apollo-client/milestone/33) for more details. ## 4.0 From c9bc6880f7805a7dc420ae90752e396e532015a2 Mon Sep 17 00:00:00 2001 From: Alessia Bellisario Date: Mon, 1 Aug 2022 16:50:49 -0400 Subject: [PATCH 02/12] chore: update renovate config and add .npmrc (#9967) --- .npmrc | 1 + renovate.json | 23 +++++++++-------------- 2 files changed, 10 insertions(+), 14 deletions(-) create mode 100644 .npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..521a9f7c077 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +legacy-peer-deps=true diff --git a/renovate.json b/renovate.json index d0f5a7a4724..fea1e741c2a 100644 --- a/renovate.json +++ b/renovate.json @@ -1,20 +1,15 @@ { - "extends": [ - "apollo-open-source" - ], + "extends": ["apollo-open-source"], "pathRules": [ { - "paths": [ - "docs/package.json" - ], - "extends": [ - "apollo-docs" - ] + "paths": ["docs/package.json"], + "extends": ["apollo-docs"] } ], - "packageRules": { - "excludePackageNames": [ - "typedoc" - ] - } + "ignoreDeps": [ + "typedoc", + "react-17", + "react-dom-17", + "@testing-library/react-12" + ] } From 0a920dba6e609a8b4a17b20da2407523de2c33ee Mon Sep 17 00:00:00 2001 From: Alessia Bellisario Date: Mon, 1 Aug 2022 21:10:27 -0400 Subject: [PATCH 03/12] chore: update CONTRIBUTING.md (#9953) --- CONTRIBUTING.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2cf7597e769..d7bd9af11a6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,12 +8,18 @@ Oh, and if you haven't already, join our [community forums](https://community.ap Here are some ways to contribute to the project, from easiest to most difficult: -* [Reporting bugs](#reporting-bugs) -* [Improving the documentation](#improving-the-documentation) -* [Responding to issues](#responding-to-issues) -* [Small bug fixes](#small-bug-fixes) -* [Suggesting features](#suggesting-features) -* [Big pull requests](#big-prs) +- [Issues](#issues) + - [Reporting bugs](#reporting-bugs) + - [Improving the documentation](#improving-the-documentation) + - [Responding to issues](#responding-to-issues) + - [Small bug fixes](#small-bug-fixes) + - [Suggesting features](#suggesting-features) +- [Big PRs](#big-prs) + - [Code review guidelines](#code-review-guidelines) +- [Development](#development) + - [Building](#building) + - [Testing](#testing) + - [Wiring a checkout into an application](#wiring-a-checkout-into-an-application) ## Issues From 792d3b589c8a0ba6a2963f6405c11d4c200263bd Mon Sep 17 00:00:00 2001 From: JV Date: Tue, 2 Aug 2022 11:27:45 -0600 Subject: [PATCH 04/12] Field policy merge docs (#9969) * added merge:false sample * Update docs/source/caching/cache-field-behavior.mdx Co-authored-by: Stephen Barlow Co-authored-by: Stephen Barlow --- docs/source/caching/cache-field-behavior.mdx | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/source/caching/cache-field-behavior.mdx b/docs/source/caching/cache-field-behavior.mdx index 297ad6209f4..c57fe661f5a 100644 --- a/docs/source/caching/cache-field-behavior.mdx +++ b/docs/source/caching/cache-field-behavior.mdx @@ -337,6 +337,27 @@ These configurations have the same behavior, but putting the `merge: true` in th Remember that mergeable objects will only be merged with existing objects occupying the same field of the same parent object, and only when the `__typename` of the objects is the same. If you really need to work around these rules, you can write a custom `merge` function to do whatever you want, but `merge: true` follows these rules. +In some cases, you might want to completely disable merge functions for certain fields. To do so, pass `merge: false` like so: + +```ts {13} +const cache = new InMemoryCache({ + typePolicies: { + Book: { + fields: { + // No longer necessary! + // author: { + // merge: true, + // }, + }, + }, + + Author: { + merge: false, + }, + }, +}); +``` + ### Merging arrays of non-normalized objects Once you're comfortable with the ideas and recommendations from the previous section, consider what happens when a `Book` can have multiple authors: From d6b0b9b7f445d159f7ff48b9895c6ea0b5ae3163 Mon Sep 17 00:00:00 2001 From: JV Date: Thu, 4 Aug 2022 09:14:50 -0600 Subject: [PATCH 05/12] add link to solid.js github repo (#9981) --- docs/source/index.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/index.mdx b/docs/source/index.mdx index d3cc1b18ee3..afc66e19d98 100644 --- a/docs/source/index.mdx +++ b/docs/source/index.mdx @@ -47,6 +47,7 @@ This documentation set focuses on React, but Apollo Client supports many other l - [Angular](https://apollo-angular.com) - [Vue](integrations/integrations/#vue) - [Svelte](integrations/integrations/#svelte) + - [Solid.js](https://github.com/merged-js/solid-apollo) (thanks to [Torsten85](https://github.com/Torsten85)) - [Ember](integrations/integrations/#ember) - [Meteor](https://www.meteor.com) (thanks to [DDP-Apollo](https://github.com/Swydo/ddp-apollo)) - Web Components From a49f2f498d6e740a278fb1b45c458ae6b6b9b5a2 Mon Sep 17 00:00:00 2001 From: hwillson Date: Thu, 4 Aug 2022 20:41:01 -0400 Subject: [PATCH 06/12] Replace crypto-hash with a custom hashing function in tests It looks like some combination of the changes in #9928 and #9942 exposed a long running issue caused by using `crypto-hash` in our `@apollo/client/link/persisted-queries` tests. `crypto-hash` spawns a thread the first time it's called, and keeps that thread alive until the end of program execution, if worker threads are available (which they are for our tests since they're running in CI via Node). Unfortunately there appears to be some kind of a race condition between `crypto-hash` `unref`ing its worker and Jest reporting a successful test suite exit, which leads to Jest reporting the following (which is seen by running jest with the `--detectOpenHandles` setting enabled): ``` Jest has detected the following X open handles potentially keeping Jest from exiting: ``` This then appears to be leading to failed tests in CI. We can look further into what's causing this race condition between `crypto-hash` and Jest, but just dropping the use of `crypto-hash` is likely a faster solution. We just need to verify that a hashing function can be successfully set and used with the persisted queries link, which means we can replace `crypto-hash` with our own simple function that doesn't use worker threads. This commit does just that by introducing a super simple custom `sha256` function that leverages Node `crypto`, and uses it instead. Fixes #9982 --- package-lock.json | 19 ------------------- package.json | 1 - src/link/persisted-queries/__tests__/index.ts | 14 +++++++++----- .../persisted-queries/__tests__/react.tsx | 7 ++----- 4 files changed, 11 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index bf51b70a4b8..2634cc5f7c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,6 @@ "acorn": "8.7.1", "bundlesize": "0.18.1", "cross-fetch": "3.1.5", - "crypto-hash": "1.3.0", "fetch-mock": "9.11.0", "glob": "8.0.3", "graphql": "16.5.0", @@ -2728,18 +2727,6 @@ "node": ">= 8" } }, - "node_modules/crypto-hash": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz", - "integrity": "sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -9936,12 +9923,6 @@ "which": "^2.0.1" } }, - "crypto-hash": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz", - "integrity": "sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==", - "dev": true - }, "cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", diff --git a/package.json b/package.json index db035464e53..63de72eac20 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,6 @@ "acorn": "8.7.1", "bundlesize": "0.18.1", "cross-fetch": "3.1.5", - "crypto-hash": "1.3.0", "fetch-mock": "9.11.0", "glob": "8.0.3", "graphql": "16.5.0", diff --git a/src/link/persisted-queries/__tests__/index.ts b/src/link/persisted-queries/__tests__/index.ts index fa0de0a9b34..05da0ff04ae 100644 --- a/src/link/persisted-queries/__tests__/index.ts +++ b/src/link/persisted-queries/__tests__/index.ts @@ -1,8 +1,8 @@ import gql from 'graphql-tag'; -import { sha256 } from 'crypto-hash'; import { print } from 'graphql'; import { times } from 'lodash'; import fetchMock from 'fetch-mock'; +import crypto from 'crypto'; import { ApolloLink, execute } from '../../core'; import { Observable } from '../../../utilities'; @@ -47,11 +47,17 @@ const errorResponse = JSON.stringify({ errors }); const giveUpResponse = JSON.stringify({ errors: giveUpErrors }); const multiResponse = JSON.stringify({ errors: multipleErrors }); +export function sha256(data: string) { + const hash = crypto.createHash('sha256'); + hash.update(data); + return hash.digest('hex'); +} + +const hash = sha256(queryString); + describe('happy path', () => { - let hash: string; beforeEach(async () => { fetchMock.restore(); - hash = hash || await sha256(queryString); }); itAsync('sends a sha256 hash of the query under extensions', (resolve, reject) => { @@ -229,10 +235,8 @@ describe('happy path', () => { }); describe('failure path', () => { - let hash: string; beforeEach(async () => { fetchMock.restore(); - hash = hash || await sha256(queryString); }); itAsync('correctly identifies the error shape from the server', (resolve, reject) => { diff --git a/src/link/persisted-queries/__tests__/react.tsx b/src/link/persisted-queries/__tests__/react.tsx index 8d5a275593c..b998d8db964 100644 --- a/src/link/persisted-queries/__tests__/react.tsx +++ b/src/link/persisted-queries/__tests__/react.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom/server'; import gql from 'graphql-tag'; import { print } from 'graphql'; -import { sha256 } from 'crypto-hash'; import fetchMock from 'fetch-mock'; import { ApolloProvider } from '../../../react/context'; @@ -13,6 +12,7 @@ import { createHttpLink } from '../../http/createHttpLink'; import { graphql } from '../../../react/hoc/graphql'; import { getDataFromTree } from '../../../react/ssr/getDataFromTree'; import { createPersistedQueryLink as createPersistedQuery, VERSION } from '../'; +import { sha256 } from './index'; // Necessary configuration in order to mock multiple requests // to a single (/graphql) endpoint @@ -49,10 +49,7 @@ const response = JSON.stringify({ data }); const response2 = JSON.stringify({ data: data2 }); const queryString = print(query); -let hash: string; -(async () => { - hash = await sha256(queryString); -})(); +const hash = sha256(queryString); describe('react application', () => { beforeEach(async () => { From b54efc2699c3f91d0c7928828fd5978309f059f5 Mon Sep 17 00:00:00 2001 From: hwillson Date: Fri, 5 Aug 2022 07:16:57 -0400 Subject: [PATCH 07/12] Fix the test report output directory JEST_JUNIT_OUTPUT is no longer a valid jest-junit environment variable. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d02ca9ae78f..0a2c38ccd5e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,7 +51,7 @@ jobs: name: Jest suite with coverage command: npm run test:ci environment: - JEST_JUNIT_OUTPUT: "reports/junit/js-test-results.xml" + JEST_JUNIT_OUTPUT_FILE: "reports/junit/js-test-results.xml" - store_test_results: path: reports/junit - store_artifacts: From 7c3c712882cf736926e94081afb28142439c1ea6 Mon Sep 17 00:00:00 2001 From: hwillson Date: Fri, 5 Aug 2022 07:17:59 -0400 Subject: [PATCH 08/12] Exclude jest-junit reports from being committed --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index f36268b0369..c133c77c1e3 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,6 @@ junit.xml # Local Netlify folder .netlify + +# Ignore generated test report output +reports From c3775158ac0877c59757ea494228dea8a89776ad Mon Sep 17 00:00:00 2001 From: hwillson Date: Fri, 5 Aug 2022 09:35:33 -0400 Subject: [PATCH 09/12] Disable Jest workers for debugging Force Jest to run all tests serially to debug process hanging. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 63de72eac20..d424da864f2 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "test:ci": "npm run test:coverage && npm run test:memory", "test:watch": "jest --config ./config/jest.config.js --watch", "test:memory": "cd scripts/memory && npm i && npm test", - "test:coverage": "npm run coverage -- --ci --maxWorkers=2 --reporters=default --reporters=jest-junit", + "test:coverage": "npm run coverage -- --ci --runInBand --reporters=default --reporters=jest-junit", "coverage": "jest --config ./config/jest.config.js --verbose --coverage", "bundlesize": "npm run build && bundlesize", "predeploy": "npm run build", From 4dda3a56c4e1a774099bab9782fdf8dac04af81d Mon Sep 17 00:00:00 2001 From: JV Date: Fri, 5 Aug 2022 14:30:51 -0600 Subject: [PATCH 10/12] adds broadcast false details (#9978) Co-authored-by: Hugh Willson --- docs/source/api/cache/InMemoryCache.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/api/cache/InMemoryCache.mdx b/docs/source/api/cache/InMemoryCache.mdx index 07a8c3144eb..ebff5868fa4 100644 --- a/docs/source/api/cache/InMemoryCache.mdx +++ b/docs/source/api/cache/InMemoryCache.mdx @@ -272,7 +272,7 @@ By specifying the ID of another cached object, you can modify arbitrary cached d -If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. +If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. If `false`, silences the broadcast of cache updates and prevents automatic query refresh. The default value is `true`. @@ -403,7 +403,7 @@ By specifying the ID of another cached object, you can modify arbitrary cached d -If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. +If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. If `false`, silences the broadcast of cache updates and prevents automatic query refresh. The default value is `true`. @@ -724,7 +724,7 @@ A map of any GraphQL variable names and values required by `fragment`. -If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. +If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. If `false`, silences the broadcast of cache updates and prevents automatic query refresh. The default value is `true`. @@ -862,7 +862,7 @@ A map of any GraphQL variable names and values required by `fragment`. -If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. +If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. If `false`, silences the broadcast of cache updates and prevents automatic query refresh. The default value is `true`. @@ -1021,7 +1021,7 @@ The default value is `false`. -If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. +If `true`, automatically refresh all active queries that depend on at least one field that's modified by this call. If `false`, silences the broadcast of cache updates and prevents automatic query refresh. The default value is `true`. @@ -1243,7 +1243,7 @@ Otherwise, all instances of the field are removed for the cached object. -If `true`, automatically refresh all active queries that depend on at least one field that's removed by this call. +If `true`, automatically refresh all active queries that depend on at least one field that's removed by this call. If `false`, silences the broadcast of cache updates and prevents automatic query refresh. The default value is `true`. From 0cd140692e19ca4c6796ad1b262789fd38facaa4 Mon Sep 17 00:00:00 2001 From: Nicolas Charpentier Date: Fri, 5 Aug 2022 17:02:56 -0400 Subject: [PATCH 11/12] Use function declaration instead of an arrow function for `WithApolloClient` (#9977) Co-authored-by: JV --- docs/source/api/react/hooks.mdx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/source/api/react/hooks.mdx b/docs/source/api/react/hooks.mdx index 1d6a53397b2..e0d6aaf646c 100644 --- a/docs/source/api/react/hooks.mdx +++ b/docs/source/api/react/hooks.mdx @@ -51,14 +51,15 @@ One way to access the configured Apollo Client instance directly is to create an ### Example ```jsx -import React from 'react'; import { ApolloConsumer } from '@apollo/client'; -const WithApolloClient = () => ( - - {client => 'We have access to the client!' /* do stuff here */} - -); +function WithApolloClient() { + return ( + + {client => 'We have access to the client!' /* do stuff here */} + + ); +} ``` ## `useQuery` From 2c57dd4020a7c690135a48fa9eeb1b2391de8107 Mon Sep 17 00:00:00 2001 From: Trevor Blades Date: Fri, 5 Aug 2022 14:46:01 -0700 Subject: [PATCH 12/12] Update code block meta strings to make syntax highlighting work again (#9985) Co-authored-by: Hugh Willson Co-authored-by: JV --- docs/source/caching/cache-field-behavior.mdx | 6 +++--- docs/source/pagination/key-args.mdx | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/source/caching/cache-field-behavior.mdx b/docs/source/caching/cache-field-behavior.mdx index c57fe661f5a..179e3a38ca3 100644 --- a/docs/source/caching/cache-field-behavior.mdx +++ b/docs/source/caching/cache-field-behavior.mdx @@ -176,7 +176,7 @@ You can use a `merge` function to intelligently combine nested objects that are -```ts{6-8} +```ts {6-8} const cache = new InMemoryCache({ typePolicies: { Book: { @@ -219,7 +219,7 @@ With this schema, our cache can normalize `Book` objects because they have an `i Now, let's say our client executes the following two queries, in order: -```graphql{5,14} +```graphql {5,14} query BookWithAuthorName { favoriteBook { id @@ -256,7 +256,7 @@ When the _first_ query returns, Apollo Client writes a `Book` object like the fo Now, when the _second_ query returns, the cached `Book` object is updated to the following: -```json{6} +```json {6} { "__typename": "Book", "id": "abc123", diff --git a/docs/source/pagination/key-args.mdx b/docs/source/pagination/key-args.mdx index 31a4f95a20a..d30cb899412 100644 --- a/docs/source/pagination/key-args.mdx +++ b/docs/source/pagination/key-args.mdx @@ -9,7 +9,7 @@ The Apollo Client cache can store multiple entries for a single schema field. By For example, consider this `Query.user` field: -```graphql{3} +```graphql {3} type Query { # Returns whichever User object corresponds to `id` user(id: ID!): User @@ -18,7 +18,7 @@ type Query { If we query for `User`s with `id`s `1` and `2`, the Apollo Client cache stores entries for _both_ like so: -```js{3,6}:title=Cache +```js {3,6} title="Cache" { 'ROOT_QUERY': { 'user({"id":"1"})': { @@ -43,7 +43,7 @@ Certain arguments _shouldn't_ cause the Apollo Client cache to store a separate Consider this `Query.feed` field: -```graphql{2} +```graphql {2} type Query { feed(offset: Int, limit: Int, category: Category): [FeedItem!] } @@ -65,7 +65,7 @@ query GetFeedItems { But because their argument values differ, these two lists of ten items are cached _separately_ by default. This means that when the second query completes, the returned items _aren't_ appended to the original list in the feed! -```js{3-4,10-11}:title=Cache +```js {3-4,10-11} title="Cache" { 'ROOT_QUERY': { // First query @@ -94,7 +94,7 @@ To help handle this case, we can [set key arguments](#setting-keyargs) for the f A **key argument** is an argument for a GraphQL field that's included in cache storage keys for that field. By default, _all_ GraphQL arguments are key arguments, as shown in our feed example: -```js{3-4,10-11}:title=Cache +```js {3-4,10-11} title="Cache" { 'ROOT_QUERY': { // First query @@ -117,7 +117,7 @@ A **key argument** is an argument for a GraphQL field that's included in cache s You can override this default behavior by defining a cache [field policy](../caching/cache-field-behavior) for a particular field: -```js{5-7} +```js {5-7} const cache = new InMemoryCache({ typePolicies: { Query: { @@ -213,7 +213,7 @@ When deciding which of a field's arguments to include in `keyArgs`, it's helpful If all arguments are key arguments (this is the default behavior), every distinct combination of argument values for a field results in a distinct cache entry. In other words, changing any argument value results in a different storage key, so the returned value is stored separately. We see this in our pagination example: -```js{3-4,10-11}:title=Cache +```js {3-4,10-11} title="Cache" { 'ROOT_QUERY': { // First query @@ -236,7 +236,7 @@ If all arguments are key arguments (this is the default behavior), every distinc With this approach, Apollo Client can't return a cached value for a field unless _all_ of the field's arguments match a previously cached result. This significantly reduces the cache's hit rate, but it also prevents the cache from returning an incorrect value when differences in arguments are relevant (as with our `User` example): -```js{3,6}:title=Cache +```js {3,6} title="Cache" { 'ROOT_QUERY': { 'user({"id":"1"})': { @@ -259,7 +259,7 @@ This default behavior is often undesirable (especially for a paginated list), so Recall this `Query.feed` field from [Pagination issues](#pagination-issues): -```graphql{2} +```graphql {2} type Query { feed(offset: Int, limit: Int, category: Category): [FeedItem!] }