Skip to content

Commit

Permalink
Merge pull request #7399 from apollographql/release-3.4
Browse files Browse the repository at this point in the history
Release 3.4.0
  • Loading branch information
benjamn authored Jul 28, 2021
2 parents 336337d + 550ec23 commit b0da267
Show file tree
Hide file tree
Showing 160 changed files with 11,995 additions and 2,604 deletions.
131 changes: 129 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,132 @@
## Apollo Client 3.4.0 (not yet released)

### New documentation

- [**Refetching queries**](https://deploy-preview-7399--apollo-client-docs.netlify.app/docs/react/data/refetching/) with `client.refetchQueries`. <br/>
[@StephenBarlow](https://github.com/StephenBarlow) and [@benjamn](https://github.com/benjamn) in [#8265](https://github.com/apollographql/apollo-client/pull/8265)

### Improvements

- `InMemoryCache` now _guarantees_ that any two result objects returned by the cache (from `readQuery`, `readFragment`, etc.) will be referentially equal (`===`) if they are deeply equal. Previously, `===` equality was often achievable for results for the same query, on a best-effort basis. Now, equivalent result objects will be automatically shared among the result trees of completely different queries. This guarantee is important for taking full advantage of optimistic updates that correctly guess the final data, and for "pure" UI components that can skip re-rendering when their input data are unchanged. <br/>
[@benjamn](https://github.com/benjamn) in [#7439](https://github.com/apollographql/apollo-client/pull/7439)

- Mutations now accept an optional callback function called `onQueryUpdated`, which will be passed the `ObservableQuery` and `Cache.DiffResult` objects for any queries invalidated by cache writes performed by the mutation's final `update` function. Using `onQueryUpdated`, you can override the default `FetchPolicy` of the query, by (for example) calling `ObservableQuery` methods like `refetch` to force a network request. This automatic detection of invalidated queries provides an alternative to manually enumerating queries using the `refetchQueries` mutation option. Also, if you return a `Promise` from `onQueryUpdated`, the mutation will automatically await that `Promise`, rendering the `awaitRefetchQueries` option unnecessary. <br/>
[@benjamn](https://github.com/benjamn) in [#7827](https://github.com/apollographql/apollo-client/pull/7827)

- Support `client.refetchQueries` as an imperative way to refetch queries, without having to pass `options.refetchQueries` to `client.mutate`. <br/>
[@dannycochran](https://github.com/dannycochran) in [#7431](https://github.com/apollographql/apollo-client/pull/7431)

- Improve standalone `client.refetchQueries` method to support automatic detection of queries needing to be refetched. <br/>
[@benjamn](https://github.com/benjamn) in [#8000](https://github.com/apollographql/apollo-client/pull/8000)

- Fix remaining barriers to loading [`@apollo/client/core`](https://cdn.jsdelivr.net/npm/@apollo/client@beta/core/+esm) as native ECMAScript modules from a CDN like [esm.run](https://www.jsdelivr.com/esm). Importing `@apollo/client` from a CDN will become possible once we move all React-related dependencies into `@apollo/client/react` in Apollo Client 4. <br/>
[@benjamn](https://github.com/benjamn) in [#8266](https://github.com/apollographql/apollo-client/issues/8266)

- `InMemoryCache` supports a new method called `batch`, which is similar to `performTransaction` but takes named options rather than positional parameters. One of these named options is an `onDirty(watch, diff)` callback, which can be used to determine which watched queries were invalidated by the `batch` operation. <br/>
[@benjamn](https://github.com/benjamn) in [#7819](https://github.com/apollographql/apollo-client/pull/7819)

- Allow `merge: true` field policy to merge `Reference` objects with non-normalized objects, and vice-versa. <br/>
[@benjamn](https://github.com/benjamn) in [#7778](https://github.com/apollographql/apollo-client/pull/7778)

- Allow identical subscriptions to be deduplicated by default, like queries. <br/>
[@jkossis](https://github.com/jkossis) in [#6910](https://github.com/apollographql/apollo-client/pull/6910)

- Always use `POST` request when falling back to sending full query with `@apollo/client/link/persisted-queries`. <br/>
[@rieset](https://github.com/rieset) in [#7456](https://github.com/apollographql/apollo-client/pull/7456)

- The `FetchMoreQueryOptions` type now takes two instead of three type parameters (`<TVariables, TData>`), thanks to using `Partial<TVariables>` instead of `K extends typeof TVariables` and `Pick<TVariables, K>`. <br/>
[@ArnaudBarre](https://github.com/ArnaudBarre) in [#7476](https://github.com/apollographql/apollo-client/pull/7476)

- Pass `variables` and `context` to a mutation's `update` function. **Note:** The type of the `update` function is now named `MutationUpdaterFunction` rather than `MutationUpdaterFn`, since the older type was [broken beyond repair](https://github.com/apollographql/apollo-client/issues/8506#issuecomment-881706613). If you are using `MutationUpdaterFn` in your own code, please use `MutationUpdaterFunction` instead. <br/>
[@jcreighton](https://github.com/jcreighton) in [#7902](https://github.com/apollographql/apollo-client/pull/7902)

- A `resultCacheMaxSize` option may be passed to the `InMemoryCache` constructor to limit the number of result objects that will be retained in memory (to speed up repeated reads), and calling `cache.reset()` now releases all such memory. <br/>
[@SofianHn](https://github.com/SofianHn) in [#8701](https://github.com/apollographql/apollo-client/pull/8701)

- Fully remove result cache entries from LRU dependency system when the corresponding entities are removed from `InMemoryCache` by eviction, or by any other means. <br/>
[@sofianhn](https://github.com/sofianhn) and [@benjamn](https://github.com/benjamn) in [#8147](https://github.com/apollographql/apollo-client/pull/8147)

- Expose missing field errors in results. <br/>
[@brainkim](github.com/brainkim) in [#8262](https://github.com/apollographql/apollo-client/pull/8262)

- Add expected/received `variables` to `No more mocked responses...` error messages generated by `MockLink`. <br/>
[@markneub](github.com/markneub) in [#8340](https://github.com/apollographql/apollo-client/pull/8340)

- The `InMemoryCache` version of the `cache.gc` method now supports additional options for removing non-essential (recomputable) result caching data. <br/>
[@benjamn](https://github.com/benjamn) in [#8421](https://github.com/apollographql/apollo-client/pull/8421)

- Suppress noisy `Missing cache result fields...` warnings by default unless `setLogVerbosity("debug")` called. <br/>
[@benjamn](https://github.com/benjamn) in [#8489](https://github.com/apollographql/apollo-client/pull/8489)

- Improve interaction between React hooks and React Fast Refresh in development. <br/>
[@andreialecu](https://github.com/andreialecu) in [#7952](https://github.com/apollographql/apollo-client/pull/7952)

### Potentially disruptive changes

- To avoid retaining sensitive information from mutation root field arguments, Apollo Client v3.4 automatically clears any `ROOT_MUTATION` fields from the cache after each mutation finishes. If you need this information to remain in the cache, you can prevent the removal by passing the `keepRootFields: true` option to `client.mutate`. `ROOT_MUTATION` result data are also passed to the mutation `update` function, so we recommend obtaining the results that way, rather than using `keepRootFields: true`, if possible. <br/>
[@benjamn](https://github.com/benjamn) in [#8280](https://github.com/apollographql/apollo-client/pull/8280)

- Internally, Apollo Client now controls the execution of development-only code using the `__DEV__` global variable, rather than `process.env.NODE_ENV`. While this change should not cause any visible differences in behavior, it will increase your minified+gzip bundle size by more than 3.5kB, unless you configure your minifier to replace `__DEV__` with a `true` or `false` constant, the same way you already replace `process.env.NODE_ENV` with a string literal like `"development"` or `"production"`. For an example of configuring a Create React App project without ejecting, see this pull request for our [React Apollo reproduction template](https://github.com/apollographql/react-apollo-error-template/pull/51). <br/>
[@benjamn](https://github.com/benjamn) in [#8347](https://github.com/apollographql/apollo-client/pull/8347)

- Internally, Apollo Client now uses namespace syntax (e.g. `import * as React from "react"`) for imports whose types are re-exported (and thus may appear in `.d.ts` files). This change should remove any need to configure `esModuleInterop` or `allowSyntheticDefaultImports` in `tsconfig.json`, but might require updating bundler configurations that specify named exports of the `react` and `prop-types` packages, to include exports like `createContext` and `createElement` ([example](https://github.com/apollographql/apollo-client/commit/16b08e1af9ba9934041298496e167aafb128c15d)). <br/>
[@devrelm](https://github.com/devrelm) in [#7742](https://github.com/apollographql/apollo-client/pull/7742)

- Respect `no-cache` fetch policy (by not reading any `data` from the cache) for `loading: true` results triggered by `notifyOnNetworkStatusChange: true`. <br />
[@jcreighton](https://github.com/jcreighton) in [#7761](https://github.com/apollographql/apollo-client/pull/7761)

- The TypeScript return types of the `getLastResult` and `getLastError` methods of `ObservableQuery` now correctly include the possibility of returning `undefined`. If you happen to be calling either of these methods directly, you may need to adjust how the calling code handles the methods' possibly-`undefined` results. <br/>
[@benjamn](https://github.com/benjamn) in [#8394](https://github.com/apollographql/apollo-client/pull/8394)

- Log non-fatal `invariant.error` message when fields are missing from result objects written into `InMemoryCache`, rather than throwing an exception. While this change relaxes an exception to be merely an error message, which is usually a backwards-compatible change, the error messages are logged in more cases now than the exception was previously thrown, and those new error messages may be worth investigating to discover potential problems in your application. The errors are not displayed for `@client`-only fields, so adding `@client` is one way to handle/hide the errors for local-only fields. Another general strategy is to use a more precise query to write specific subsets of data into the cache, rather than reusing a larger query that contains fields not present in the written `data`. <br/>
[@benjamn](https://github.com/benjamn) in [#8416](https://github.com/apollographql/apollo-client/pull/8416)

- The [`nextFetchPolicy`](https://github.com/apollographql/apollo-client/pull/6893) option for `client.watchQuery` and `useQuery` will no longer be removed from the `options` object after it has been applied, and instead will continue to be applied any time `options.fetchPolicy` is reset to another value, until/unless the `options.nextFetchPolicy` property is removed from `options`. <br/>
[@benjamn](https://github.com/benjamn) in [#8465](https://github.com/apollographql/apollo-client/pull/8465)

- The `fetchMore`, `subscribeToMore`, and `updateQuery` functions returned from the `useQuery` hook may now return undefined in edge cases where the functions are called when the component is unmounted <br/> [@noghartt](https://github.com/noghartt) in [#7980](https://github.com/apollographql/apollo-client/pull/7980).

### Bug fixes

- In Apollo Client 2.x, a `refetch` operation would always replace existing data in the cache. With the introduction of field policy `merge` functions in Apollo Client 3, existing field values could be inappropriately combined with incoming field values by a custom `merge` function that does not realize a `refetch` has happened.

To give you more control over this behavior, we have introduced an `overwrite?: boolean = false` option for `cache.writeQuery` and `cache.writeFragment`, and an option called `refetchWritePolicy?: "merge" | "overwrite"` for `client.watchQuery`, `useQuery`, and other functions that accept `WatchQueryOptions`. You can use these options to make sure any `merge` functions involved in cache writes for `refetch` operations get invoked with `undefined` as their first argument, which simulates the absence of any existing data, while still giving the `merge` function a chance to determine the internal representation of the incoming data.

The default behaviors are `overwrite: true` and `refetchWritePolicy: "overwrite"`, which restores the Apollo Client 2.x behavior, but (if this change causes any problems for your application) you can easily recover the previous merging behavior by setting a default value for `refetchWritePolicy` in `defaultOptions.watchQuery`:
```ts
new ApolloClient({
defaultOptions: {
watchQuery: {
refetchWritePolicy: "merge",
},
},
})
```
[@benjamn](https://github.com/benjamn) in [#7810](https://github.com/apollographql/apollo-client/pull/7810)

- Make sure the `MockedResponse` `ResultFunction` type is re-exported. <br/>
[@hwillson](https://github.com/hwillson) in [#8315](https://github.com/apollographql/apollo-client/pull/8315)

- Fix polling when used with `skip`. <br/>
[@brainkim](https://github.com/brainkim) in [#8346](https://github.com/apollographql/apollo-client/pull/8346)

- `InMemoryCache` now coalesces `EntityStore` updates to guarantee only one `store.merge(id, fields)` call per `id` per cache write. <br/>
[@benjamn](https://github.com/benjamn) in [#8372](https://github.com/apollographql/apollo-client/pull/8372)

- Fix polling when used with `<React.StrictMode>`. <br/>
[@brainkim](https://github.com/brainkim) in [#8414](https://github.com/apollographql/apollo-client/pull/8414)

- Fix the React integration logging `Warning: Can't perform a React state update on an unmounted component`. <br/>
[@wuarmin](https://github.com/wuarmin) in [#7745](https://github.com/apollographql/apollo-client/pull/7745)

- Make `ObservableQuery#getCurrentResult` always call `queryInfo.getDiff()`. <br/>
[@benjamn](https://github.com/benjamn) in [#8422](https://github.com/apollographql/apollo-client/pull/8422)

- Make `readField` default to reading from current object only when the `from` option/argument is actually omitted, not when `from` is passed to `readField` with an undefined value. A warning will be printed when this situation occurs. <br/>
[@benjamn](https://github.com/benjamn) in [#8508](https://github.com/apollographql/apollo-client/pull/8508)

- The `fetchMore`, `subscribeToMore`, and `updateQuery` functions no longer throw `undefined` errors <br/> [@noghartt](https://github.com/noghartt) in [#7980](https://github.com/apollographql/apollo-client/pull/7980).

## Apollo Client 3.3.21

### Bug fixes
Expand Down Expand Up @@ -61,8 +190,6 @@

## Apollo Client 3.3.15

### Bug fixes

- Increment `queryInfo.lastRequestId` only when making a network request through the `ApolloLink` chain, rather than every time `fetchQueryByPolicy` is called. <br/>
[@dannycochran](https://github.com/dannycochran) in [#7956](https://github.com/apollographql/apollo-client/pull/7956)

Expand Down
5 changes: 4 additions & 1 deletion config/entryPoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ const entryPoints = [
{ dirs: ['react', 'hooks'] },
{ dirs: ['react', 'parser'] },
{ dirs: ['react', 'ssr'] },
{ dirs: ['utilities'] },
{ dirs: ['utilities'],
sideEffects: [
"./globals/**"
]},
{ dirs: ['testing'], extensions: [".js", ".jsx"] },
];

Expand Down
2 changes: 1 addition & 1 deletion config/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function eachFile(dir: string, callback: (
) => any) {
const promises: Promise<any>[] = [];

return new Promise((resolve, reject) => {
return new Promise<void>((resolve, reject) => {
glob(`${dir}/**/*.js`, (error, files) => {
if (error) return reject(error);

Expand Down
3 changes: 2 additions & 1 deletion config/prepareDist.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ fs.copyFileSync(`${srcDir}/LICENSE`, `${destDir}/LICENSE`);
entryPoints.forEach(function buildPackageJson({
dirs,
bundleName = dirs[dirs.length - 1],
sideEffects = false,
}) {
if (!dirs.length) return;
fs.writeFileSync(
Expand All @@ -71,7 +72,7 @@ entryPoints.forEach(function buildPackageJson({
main: `${bundleName}.cjs.js`,
module: 'index.js',
types: 'index.d.ts',
sideEffects: false,
sideEffects,
}, null, 2) + "\n",
);
});
47 changes: 18 additions & 29 deletions config/processInvariants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,50 +71,50 @@ function transform(code: string, file: string) {
const node = path.node;

if (isCallWithLength(node, "invariant", 1)) {
if (isNodeEnvConditional(path.parent.node)) {
if (isDEVConditional(path.parent.node)) {
return;
}

const newArgs = node.arguments.slice(0, 1);
newArgs.push(getErrorCode(file, node));

return b.conditionalExpression(
makeNodeEnvTest(),
makeDEVExpr(),
node,
b.callExpression.from({
...node,
arguments: newArgs,
}),
node,
);
}

if (node.callee.type === "MemberExpression" &&
isIdWithName(node.callee.object, "invariant") &&
isIdWithName(node.callee.property, "warn", "error")) {
if (isNodeEnvLogicalOr(path.parent.node)) {
isIdWithName(node.callee.property, "debug", "log", "warn", "error")) {
if (isDEVLogicalAnd(path.parent.node)) {
return;
}
return b.logicalExpression("||", makeNodeEnvTest(), node);
return b.logicalExpression("&&", makeDEVExpr(), node);
}
},

visitNewExpression(path) {
this.traverse(path);
const node = path.node;
if (isCallWithLength(node, "InvariantError", 0)) {
if (isNodeEnvConditional(path.parent.node)) {
if (isDEVConditional(path.parent.node)) {
return;
}

const newArgs = [getErrorCode(file, node)];

return b.conditionalExpression(
makeNodeEnvTest(),
makeDEVExpr(),
node,
b.newExpression.from({
...node,
arguments: newArgs,
}),
node,
);
}
}
Expand All @@ -137,32 +137,21 @@ function isCallWithLength(
node.arguments.length > length;
}

function isNodeEnvConditional(node: Node) {
function isDEVConditional(node: Node) {
return n.ConditionalExpression.check(node) &&
isNodeEnvExpr(node.test);
isDEVExpr(node.test);
}

function isNodeEnvLogicalOr(node: Node) {
function isDEVLogicalAnd(node: Node) {
return n.LogicalExpression.check(node) &&
node.operator === "||" &&
isNodeEnvExpr(node.left);
node.operator === "&&" &&
isDEVExpr(node.left);
}

function makeNodeEnvTest() {
return b.binaryExpression(
"===",
b.memberExpression(
b.memberExpression(
b.identifier("process"),
b.identifier("env")
),
b.identifier("NODE_ENV"),
),
b.stringLiteral("production"),
);
function makeDEVExpr() {
return b.identifier("__DEV__");
}

const referenceNodeEnvExpr = makeNodeEnvTest();
function isNodeEnvExpr(node: Node) {
return recast.types.astNodesAreEquivalent(node, referenceNodeEnvExpr);
function isDEVExpr(node: Node) {
return isIdWithName(node, "__DEV__");
}
Loading

0 comments on commit b0da267

Please sign in to comment.