diff --git a/.api-reports/api-report-core.md b/.api-reports/api-report-core.md index 04da92c9c0a..54622181969 100644 --- a/.api-reports/api-report-core.md +++ b/.api-reports/api-report-core.md @@ -109,8 +109,6 @@ export class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; getObservableQueries(include?: RefetchQueriesInclude): Map>; getResolvers(): Resolvers; diff --git a/.api-reports/api-report-react.md b/.api-reports/api-report-react.md index c6de1672ff0..14db26ad941 100644 --- a/.api-reports/api-report-react.md +++ b/.api-reports/api-report-react.md @@ -120,8 +120,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report-react_components.md b/.api-reports/api-report-react_components.md index 0775e0c9cbb..fed0f1ea60b 100644 --- a/.api-reports/api-report-react_components.md +++ b/.api-reports/api-report-react_components.md @@ -120,8 +120,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report-react_context.md b/.api-reports/api-report-react_context.md index c93ef634c07..01f8cfa71d1 100644 --- a/.api-reports/api-report-react_context.md +++ b/.api-reports/api-report-react_context.md @@ -119,8 +119,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report-react_hoc.md b/.api-reports/api-report-react_hoc.md index ca318274946..044cb10cc77 100644 --- a/.api-reports/api-report-react_hoc.md +++ b/.api-reports/api-report-react_hoc.md @@ -119,8 +119,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report-react_hooks.md b/.api-reports/api-report-react_hooks.md index f6d137505ce..3296d232fd0 100644 --- a/.api-reports/api-report-react_hooks.md +++ b/.api-reports/api-report-react_hooks.md @@ -118,8 +118,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report-react_internal.md b/.api-reports/api-report-react_internal.md index 6eab8934062..a54ec58ee63 100644 --- a/.api-reports/api-report-react_internal.md +++ b/.api-reports/api-report-react_internal.md @@ -118,8 +118,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report-react_ssr.md b/.api-reports/api-report-react_ssr.md index 060eb9c79e6..8f22892c265 100644 --- a/.api-reports/api-report-react_ssr.md +++ b/.api-reports/api-report-react_ssr.md @@ -119,8 +119,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report-testing.md b/.api-reports/api-report-testing.md index 57c3dc01694..54327b058c4 100644 --- a/.api-reports/api-report-testing.md +++ b/.api-reports/api-report-testing.md @@ -119,8 +119,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report-testing_core.md b/.api-reports/api-report-testing_core.md index 341da7c1d35..1b505f4d121 100644 --- a/.api-reports/api-report-testing_core.md +++ b/.api-reports/api-report-testing_core.md @@ -118,8 +118,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report-utilities.md b/.api-reports/api-report-utilities.md index 1478b419cec..8028dbdf360 100644 --- a/.api-reports/api-report-utilities.md +++ b/.api-reports/api-report-utilities.md @@ -131,8 +131,6 @@ class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; // Warning: (ae-forgotten-export) The symbol "RefetchQueriesInclude" needs to be exported by the entry point index.d.ts getObservableQueries(include?: RefetchQueriesInclude): Map>; diff --git a/.api-reports/api-report.md b/.api-reports/api-report.md index 9057e4f8f2a..627586c9bd9 100644 --- a/.api-reports/api-report.md +++ b/.api-reports/api-report.md @@ -111,8 +111,6 @@ export class ApolloClient implements DataProxy { get documentTransform(): DocumentTransform; extract(optimistic?: boolean): TCacheShape; // Warning: (ae-forgotten-export) The symbol "getApolloClientMemoryInternals" needs to be exported by the entry point index.d.ts - // - // @internal getMemoryInternals?: typeof getApolloClientMemoryInternals; getObservableQueries(include?: RefetchQueriesInclude): Map>; getResolvers(): Resolvers; diff --git a/config/apiExtractor.ts b/config/apiExtractor.ts index f50d25a875a..f64b0d7b525 100644 --- a/config/apiExtractor.ts +++ b/config/apiExtractor.ts @@ -6,6 +6,7 @@ import { IConfigFile, } from "@microsoft/api-extractor"; import { parseArgs } from "node:util"; +import fs from "node:fs"; // @ts-ignore import { map } from "./entryPoints.js"; @@ -40,37 +41,67 @@ const packageJsonFullPath = path.resolve(__dirname, "../package.json"); process.exitCode = 0; -map((entryPoint: { dirs: string[] }) => { - if (entryPoint.dirs.length > 0 && parsed.values["main-only"]) return; +const tempDir = fs.mkdtempSync("api-model"); +try { + if (parsed.values.generate?.includes("docModel")) { + console.log( + "\n\nCreating API extractor docmodel for the a combination of all entry points" + ); + const dist = path.resolve(__dirname, "../dist"); + const entryPoints = map((entryPoint: { dirs: string[] }) => { + return `export * from "${dist}/${entryPoint.dirs.join("/")}/index.d.ts";`; + }).join("\n"); + const entryPointFile = path.join(tempDir, "entry.d.ts"); + fs.writeFileSync(entryPointFile, entryPoints); + + buildReport(entryPointFile, "docModel"); + } - const path = entryPoint.dirs.join("/"); - const mainEntryPointFilePath = - `/dist/${path}/index.d.ts`.replace("//", "/"); - console.log( - "\n\nCreating API extractor report for " + mainEntryPointFilePath - ); + if (parsed.values.generate?.includes("apiReport")) { + map((entryPoint: { dirs: string[] }) => { + const path = entryPoint.dirs.join("/"); + const mainEntryPointFilePath = + `/dist/${path}/index.d.ts`.replace("//", "/"); + console.log( + "\n\nCreating API extractor report for " + mainEntryPointFilePath + ); + buildReport( + mainEntryPointFilePath, + "apiReport", + `api-report${path ? "-" + path.replace(/\//g, "_") : ""}.md` + ); + }); + } +} finally { + fs.rmSync(tempDir, { recursive: true }); +} +function buildReport( + mainEntryPointFilePath: string, + mode: "apiReport" | "docModel", + reportFileName = "" +) { const configObject: IConfigFile = { ...(JSON.parse(JSON.stringify(baseConfig)) as IConfigFile), mainEntryPointFilePath, }; - configObject.apiReport!.reportFileName = `api-report${ - path ? "-" + path.replace(/\//g, "_") : "" - }.md`; - - configObject.apiReport!.enabled = - parsed.values.generate?.includes("apiReport") || false; - - configObject.docModel!.enabled = - parsed.values.generate?.includes("docModel") || false; - - if (entryPoint.dirs.length !== 0) { + if (mode === "apiReport") { + configObject.apiReport!.enabled = true; configObject.docModel = { enabled: false }; - configObject.tsdocMetadata = { enabled: false }; configObject.messages!.extractorMessageReporting![ "ae-unresolved-link" ]!.logLevel = ExtractorLogLevel.None; + configObject.apiReport!.reportFileName = reportFileName; + } else { + configObject.docModel!.enabled = true; + configObject.apiReport = { + enabled: false, + // this has to point to an existing folder, otherwise the extractor will fail + // but it will not write the file + reportFileName: "disabled.md", + reportFolder: tempDir, + }; } const extractorConfig = ExtractorConfig.prepare({ @@ -85,22 +116,23 @@ map((entryPoint: { dirs: string[] }) => { }); let succeededAdditionalChecks = true; - const contents = readFileSync(extractorConfig.reportFilePath, "utf8"); - - if (contents.includes("rehackt")) { - succeededAdditionalChecks = false; - console.error( - "❗ %s contains a reference to the `rehackt` package!", - extractorConfig.reportFilePath - ); - } - if (contents.includes('/// ')) { - succeededAdditionalChecks = false; - console.error( - "❗ %s contains a reference to the global `React` type!/n" + - 'Use `import type * as ReactTypes from "react";` instead', - extractorConfig.reportFilePath - ); + if (fs.existsSync(extractorConfig.reportFilePath)) { + const contents = readFileSync(extractorConfig.reportFilePath, "utf8"); + if (contents.includes("rehackt")) { + succeededAdditionalChecks = false; + console.error( + "❗ %s contains a reference to the `rehackt` package!", + extractorConfig.reportFilePath + ); + } + if (contents.includes('/// ')) { + succeededAdditionalChecks = false; + console.error( + "❗ %s contains a reference to the global `React` type!/n" + + 'Use `import type * as ReactTypes from "react";` instead', + extractorConfig.reportFilePath + ); + } } if (extractorResult.succeeded && succeededAdditionalChecks) { @@ -115,4 +147,4 @@ map((entryPoint: { dirs: string[] }) => { } process.exitCode = 1; } -}); +} diff --git a/docs/shared/ApiDoc/DocBlock.js b/docs/shared/ApiDoc/DocBlock.js index 333bda75afd..157ece36fdc 100644 --- a/docs/shared/ApiDoc/DocBlock.js +++ b/docs/shared/ApiDoc/DocBlock.js @@ -138,7 +138,7 @@ export function Example({ if (!value) return null; return ( - {mdToReact(value)} + {mdToReact(value)} ); } diff --git a/docs/shared/ApiDoc/PropertySignatureTable.js b/docs/shared/ApiDoc/PropertySignatureTable.js index 317b2926f0f..b5d31feb18d 100644 --- a/docs/shared/ApiDoc/PropertySignatureTable.js +++ b/docs/shared/ApiDoc/PropertySignatureTable.js @@ -98,7 +98,12 @@ export function PropertySignatureTable({ - + ))} diff --git a/docs/source/caching/memory-management.mdx b/docs/source/caching/memory-management.mdx new file mode 100644 index 00000000000..cf40fc27d8d --- /dev/null +++ b/docs/source/caching/memory-management.mdx @@ -0,0 +1,126 @@ +--- +title: Memory management +api_doc: + - "@apollo/client!CacheSizes:interface" + - "@apollo/client!ApolloClient:class" +subtitle: Learn how to choose and set custom cache sizes +description: Learn how to choose and set custom cache sizes with Apollo Client. +minVersion: 3.9.0 +--- + +import { Remarks, PropertySignatureTable, Example } from '../../shared/ApiDoc'; + +## Cache Sizes + +For better performance, Apollo Client caches (or, in other words, memoizes) many +internally calculated values. +In most cases, these values are cached in [weak caches](https://en.wikipedia.org/wiki/Weak_reference), which means that if the +source object is garbage-collected, the cached value will be garbage-collected, +too. + +These caches are also Least Recently Used (LRU) caches, meaning that if the cache is full, +the least recently used value will be garbage-collected. + +Depending on your application, you might want to tweak the cache size to fit your +needs. + +You can set your cache size [before (recommended)](#setting-cache-sizes-before-loading-the-apollo-client-library) or [after](#adjusting-cache-sizes-after-loading-the-apollo-client-library) loading the Apollo Client library. + +### Setting cache sizes before loading the Apollo Client library + +Setting cache sizes before loading the Apollo Client library is recommended because some caches are already initialized when the library is loaded. Changed cache sizes only +affect caches created after the fact, so you'd have to write additional runtime code to recreate these caches after changing their size. + + ```ts +import type { CacheSizes } from '@apollo/client/utilities'; + + globalThis[Symbol.for("apollo.cacheSize")] = { + parser: 100, + "fragmentRegistry.lookup": 500 + } satisfies Partial + ``` + +### Adjusting cache sizes after loading the Apollo Client library + +You can also adjust cache sizes after loading the library. + +```js +import { cacheSizes } from '@apollo/client/utilities'; +import { print } from '@apollo/client' + +cacheSizes.print = 100; +// cache sizes changed this way will only take effect for caches +// created after the cache size has been changed, so we need to +// reset the cache for it to be effective + +print.reset(); +``` + +### Choosing appropriate cache sizes + + + +To choose good sizes for our memoization caches, you need to know what they +use as source values, and have a general understanding of the data flow inside of +Apollo Client. + +For most memoized values, the source value is a parsed GraphQL document— +a `DocumentNode`. There are two types: + +* **User-supplied `DocumentNode`s** are created + by the user, for example by using the `gql` template literal tag. + This is the `QUERY`, `MUTATION`, or `SUBSCRIPTION` argument passed + into a [`useQuery` hook](../data/queries/#usequery-api) or as the `query` option to `client.query`. +* **Transformed `DocumentNode`s** are derived from + user-supplied `DocumentNode`s, for example, by applying [`DocumentTransform`s](../data/document-transforms/) to them. + +As a rule of thumb, you should set the cache sizes for caches using a transformed +`DocumentNode` at least to the same size as for caches using a user-supplied +`DocumentNode`. If your application uses a custom `DocumentTransform` that does +not always transform the same input to the same output, you should set the cache +size for caches using a Transformed `DocumentNode` to a higher value than for +caches using a user-supplied `DocumentNode`. + +By default, Apollo Client uses a base value of 1000 cached objects for caches using +user-supplied `DocumentNode` instances, and scales other cache sizes relative +to that. For example, the default base value of 1000 for user-provided `DocumentNode`s would scale to 2000, 4000, etc. for transformed `DocumentNode`s, depending on the transformation performed. + +This base value should be plenty for most applications, but you can tweak them if you have different requirements. + +#### Measuring cache usage + +Since estimating appropriate cache sizes for your application can be hard, Apollo Client +exposes an API for cache usage measurement.
+This way, you can click around in your application and then take a look at the +actual usage of the memoizing caches. + +Keep in mind that this API is primarily meant for usage with the Apollo DevTools +(an integration is coming soon), and the API may change at any +point in time.
+It is also only included in development builds, not in production builds. + + + +The cache usage API is only meant for manual measurements. Don't rely on it in production code or tests. + + + + + + + +### Cache options + + diff --git a/docs/source/config.json b/docs/source/config.json index 6862f2e7836..60b6f0b1b6e 100644 --- a/docs/source/config.json +++ b/docs/source/config.json @@ -28,6 +28,7 @@ "Reading and writing": "/caching/cache-interaction", "Garbage collection and eviction": "/caching/garbage-collection", "Customizing field behavior": "/caching/cache-field-behavior", + "Memory Management": "/caching/memory-management", "Advanced topics": "/caching/advanced-topics" }, "Pagination": { diff --git a/src/core/ApolloClient.ts b/src/core/ApolloClient.ts index a3216fdda34..933d4266b1e 100644 --- a/src/core/ApolloClient.ts +++ b/src/core/ApolloClient.ts @@ -750,10 +750,83 @@ export class ApolloClient implements DataProxy { /** * @experimental - * @internal * This is not a stable API - it is used in development builds to expose * information to the DevTools. * Use at your own risk! + * For more details, see [Memory Management](https://www.apollographql.com/docs/react/caching/memory-management/#measuring-cache-usage) + * + * @example + * ```ts + * console.log(client.getMemoryInternals()) + * ``` + * Logs output in the following JSON format: + * @example + * ```json + *{ + * limits: { + * parser: 1000, + * canonicalStringify: 1000, + * print: 2000, + * 'documentTransform.cache': 2000, + * 'queryManager.getDocumentInfo': 2000, + * 'PersistedQueryLink.persistedQueryHashes': 2000, + * 'fragmentRegistry.transform': 2000, + * 'fragmentRegistry.lookup': 1000, + * 'fragmentRegistry.findFragmentSpreads': 4000, + * 'cache.fragmentQueryDocuments': 1000, + * 'removeTypenameFromVariables.getVariableDefinitions': 2000, + * 'inMemoryCache.maybeBroadcastWatch': 5000, + * 'inMemoryCache.executeSelectionSet': 10000, + * 'inMemoryCache.executeSubSelectedArray': 5000 + * }, + * sizes: { + * parser: 26, + * canonicalStringify: 4, + * print: 14, + * addTypenameDocumentTransform: [ + * { + * cache: 14, + * }, + * ], + * queryManager: { + * getDocumentInfo: 14, + * documentTransforms: [ + * { + * cache: 14, + * }, + * { + * cache: 14, + * }, + * ], + * }, + * fragmentRegistry: { + * findFragmentSpreads: 34, + * lookup: 20, + * transform: 14, + * }, + * cache: { + * fragmentQueryDocuments: 22, + * }, + * inMemoryCache: { + * executeSelectionSet: 4345, + * executeSubSelectedArray: 1206, + * maybeBroadcastWatch: 32, + * }, + * links: [ + * { + * PersistedQueryLink: { + * persistedQueryHashes: 14, + * }, + * }, + * { + * removeTypenameFromVariables: { + * getVariableDefinitions: 14, + * }, + * }, + * ], + * }, + * } + *``` */ public getMemoryInternals?: typeof getApolloClientMemoryInternals; } diff --git a/src/utilities/caching/sizes.ts b/src/utilities/caching/sizes.ts index 998537740a3..28ace70a8c2 100644 --- a/src/utilities/caching/sizes.ts +++ b/src/utilities/caching/sizes.ts @@ -9,97 +9,133 @@ declare global { /** * The cache sizes used by various Apollo Client caches. * - * Note that these caches are all derivative and if an item is cache-collected, - * it's not the end of the world - the cached item will just be recalculated. - * - * As a result, these cache sizes should not be chosen to hold every value ever - * encountered, but rather to hold a reasonable number of values that can be - * assumed to be on the screen at any given time. + * @remarks + * All configurable caches hold memoized values. If an item is + * cache-collected, it incurs only a small performance impact and + * doesn't cause data loss. A smaller cache size might save you memory. * + * You should choose cache sizes appropriate for storing a reasonable + * number of values rather than every value. To prevent too much recalculation, + * choose cache sizes that are at least large enough to hold memoized values for + * all hooks/queries on the screen at any given time. + */ +/* * We assume a "base value" of 1000 here, which is already very generous. * In most applications, it will be very unlikely that 1000 different queries * are on screen at the same time. */ export interface CacheSizes { /** - * Cache size for the [`print`](../../utilities/graphql/print.ts) function. + * Cache size for the [`print`](https://github.com/apollographql/apollo-client/blob/main/src/utilities/graphql/print.ts) function. + * + * It is called with transformed `DocumentNode`s. * * @defaultValue * Defaults to `2000`. * * @remarks - * This method is called from the `QueryManager` and various `Link`s, + * This method is called to transform a GraphQL query AST parsed by `gql` + * back into a GraphQL string. + * + * @privateRemarks + * This method is called from the `QueryManager` and various `ApolloLink`s, * always with the "serverQuery", so the server-facing part of a transformed - * DocumentNode. + * `DocumentNode`. */ print: number; /** - * Cache size for the [`parser`](../../react/parser/index.ts) function. + * Cache size for the [`parser`](https://github.com/apollographql/apollo-client/blob/main/src/react/parser/index.ts) function. + * + * It is called with user-provided `DocumentNode`s. * * @defaultValue * Defaults to `1000`. * * @remarks + * This method is called by HOCs and hooks. + * + * @privateRemarks * This function is used directly in HOCs, and nowadays mainly accessed by * calling `verifyDocumentType` from various hooks. * It is called with a user-provided DocumentNode. */ parser: number; /** - * Cache size for the `performWork` method of each [`DocumentTransform`](../../utilities/graphql/DocumentTransform.ts). + * Cache size for the cache of [`DocumentTransform`](https://github.com/apollographql/apollo-client/blob/main/src/utilities/graphql/DocumentTransform.ts) + * instances with the `cache` option set to `true`. + * + * Can be called with user-defined or already-transformed `DocumentNode`s. * * @defaultValue * Defaults to `2000`. * * @remarks - * This method is called from `transformDocument`, which is called from - * `QueryManager` with a user-provided DocumentNode. - * It is also called with already-transformed DocumentNodes, assuming the - * user provided additional transforms. + * The cache size here should be chosen with other `DocumentTransform`s in mind. + * For example, if there was a `DocumentTransform` that would take `x` `DocumentNode`s, + * and returned a differently-transformed `DocumentNode` depending if the app is + * online or offline, then we assume that the cache returns `2*x` documents. + * If that were concatenated with another `DocumentTransform` that would + * also duplicate the cache size, you'd need to account for `4*x` documents + * returned by the second transform. + * + * Due to an implementation detail of Apollo Client, if you use custom document + * transforms you should always add `n` (the "base" number of user-provided + * Documents) to the resulting cache size. * - * The cache size here should be chosen with other DocumentTransforms in mind. - * For example, if there was a DocumentTransform that would take `n` DocumentNodes, - * and returned a differently-transformed DocumentNode depending if the app is - * online or offline, then we assume that the cache returns `2*n` documents. + * If we assume that the user-provided transforms receive `n` documents and + * return `n` documents, the cache size should be `2*n`. + * + * If we assume that the chain of user-provided transforms receive `n` documents and + * return `4*n` documents, the cache size should be `5*n`. + * + * This size should also then be used in every other cache that mentions that + * it operates on a "transformed" `DocumentNode`. + * + * @privateRemarks + * Cache size for the `performWork` method of each [`DocumentTransform`](https://github.com/apollographql/apollo-client/blob/main/src/utilities/graphql/DocumentTransform.ts). * * No user-provided DocumentNode will actually be "the last one", as we run the * `defaultDocumentTransform` before *and* after the user-provided transforms. + * For that reason, we need the extra `n` here - `n` for "before transformation" + * plus the actual maximum cache size of the user-provided transform chain. * - * So if we assume that the user-provided transforms receive `n` documents and - * return `n` documents, the cache size should be `2*n`. - * - * If we assume that the user-provided transforms receive `n` documents and - * returns `2*n` documents, the cache size should be `3*n`. + * This method is called from `transformDocument`, which is called from + * `QueryManager` with a user-provided DocumentNode. + * It is also called with already-transformed DocumentNodes, assuming the + * user provided additional transforms. * - * This size should also then be used in every other cache that mentions that - * it operates on a "transformed" DocumentNode. */ "documentTransform.cache": number; /** - * Cache size for the `transformCache` used in the `getDocumentInfo` method of - * [`QueryManager`](../../core/QueryManager.ts). + * A cache inside of [`QueryManager`](https://github.com/apollographql/apollo-client/blob/main/src/core/QueryManager.ts). + * + * It is called with transformed `DocumentNode`s. * * @defaultValue * Defaults to `2000`. * - * @remarks - * `getDocumentInfo` is called throughout the `QueryManager` with transformed - * DocumentNodes. + * @privateRemarks + * Cache size for the `transformCache` used in the `getDocumentInfo` method of `QueryManager`. + * Called throughout the `QueryManager` with transformed DocumentNodes. */ "queryManager.getDocumentInfo": number; /** - * Cache size for the `hashesByQuery` cache in the [`PersistedQueryLink`](../../link/persisted-queries/index.ts). + * A cache inside of [`PersistedQueryLink`](https://github.com/apollographql/apollo-client/blob/main/src/link/persisted-queries/index.ts). + * + * It is called with transformed `DocumentNode`s. * * @defaultValue * Defaults to `2000`. * * @remarks - * This cache is used to cache the hashes of persisted queries. It is working with - * transformed DocumentNodes. + * This cache is used to cache the hashes of persisted queries. + * + * @privateRemarks + * Cache size for the `hashesByQuery` cache in the `PersistedQueryLink`. */ "PersistedQueryLink.persistedQueryHashes": number; /** - * Cache for the `sortingMap` used by [`canonicalStringify`](../../utilities/common/canonicalStringify.ts). + * Cache used by [`canonicalStringify`](https://github.com/apollographql/apollo-client/blob/main/src/utilities/common/canonicalStringify.ts). * * @defaultValue * Defaults to `1000`. @@ -110,52 +146,67 @@ export interface CacheSizes { * It uses the stringified unsorted keys of objects as keys. * The cache will not grow beyond the size of different object **shapes** * encountered in an application, no matter how much actual data gets stringified. + * + * @privateRemarks + * Cache size for the `sortingMap` in `canonicalStringify`. */ canonicalStringify: number; /** - * Cache size for the `transform` method of [`FragmentRegistry`](../../cache/inmemory/fragmentRegistry.ts). + * A cache inside of [`FragmentRegistry`](https://github.com/apollographql/apollo-client/blob/main/src/cache/inmemory/fragmentRegistry.ts). + * + * Can be called with user-defined or already-transformed `DocumentNode`s. * * @defaultValue * Defaults to `2000`. * - * @remarks + * @privateRemarks + * + * Cache size for the `transform` method of FragmentRegistry. * This function is called as part of the `defaultDocumentTransform` which will be called with * user-provided and already-transformed DocumentNodes. * */ "fragmentRegistry.transform": number; /** - * Cache size for the `lookup` method of [`FragmentRegistry`](../../cache/inmemory/fragmentRegistry.ts). + * A cache inside of [`FragmentRegistry`](https://github.com/apollographql/apollo-client/blob/main/src/cache/inmemory/fragmentRegistry.ts). + * + * This function is called with fragment names in the form of a string. * * @defaultValue * Defaults to `1000`. * * @remarks - * This function is called with fragment names in the form of a string. + * The size of this case should be chosen with the number of fragments in + * your application in mind. * * Note: - * This function is a dependency of `transform`, so having a too small cache size here + * This function is a dependency of `fragmentRegistry.transform`, so having too small of a cache size here * might involuntarily invalidate values in the `transform` cache. + * + * @privateRemarks + * Cache size for the `lookup` method of FragmentRegistry. */ "fragmentRegistry.lookup": number; /** - * Cache size for the `findFragmentSpreads` method of [`FragmentRegistry`](../../cache/inmemory/fragmentRegistry.ts). + * Cache size for the `findFragmentSpreads` method of [`FragmentRegistry`](https://github.com/apollographql/apollo-client/blob/main/src/cache/inmemory/fragmentRegistry.ts). + * + * This function is called with transformed `DocumentNode`s, as well as recursively + * with every fragment spread referenced within that, or a fragment referenced by a + * fragment spread. * * @defaultValue * Defaults to `4000`. * * @remarks - * This function is called with transformed DocumentNodes, as well as recursively - * with every fragment spread referenced within that, or a fragment referenced by a - * fragment spread. * - * Note: - * This function is a dependency of `transform`, so having a too small cache size here + * Note: This function is a dependency of `fragmentRegistry.transform`, so having too small of cache size here * might involuntarily invalidate values in the `transform` cache. */ "fragmentRegistry.findFragmentSpreads": number; /** - * Cache size for the `getFragmentDoc` method of [`ApolloCache`](../../cache/core/cache.ts). + * Cache size for the `getFragmentDoc` method of [`ApolloCache`](https://github.com/apollographql/apollo-client/blob/main/src/cache/core/cache.ts). + * + * This function is called with user-provided fragment definitions. * * @defaultValue * Defaults to `1000`. @@ -165,19 +216,21 @@ export interface CacheSizes { */ "cache.fragmentQueryDocuments": number; /** - * Cache size for the `getVariableDefinitions` function in [`removeTypenameFromVariables`](../../link/remove-typename/removeTypenameFromVariables.ts). + * Cache used in [`removeTypenameFromVariables`](https://github.com/apollographql/apollo-client/blob/main/src/link/remove-typename/removeTypenameFromVariables.ts). + * + * This function is called transformed `DocumentNode`s. * * @defaultValue * Defaults to `2000`. * - * @remarks - * This function is called in a link with transformed DocumentNodes. + * @privateRemarks + * Cache size for the `getVariableDefinitions` function of `removeTypenameFromVariables`. */ "removeTypenameFromVariables.getVariableDefinitions": number; /** - * Cache size for the `maybeBroadcastWatch` method on [`InMemoryCache`](../../cache/inmemory/inMemoryCache.ts). + * Cache size for the `maybeBroadcastWatch` method on [`InMemoryCache`](https://github.com/apollographql/apollo-client/blob/main/src/cache/inmemory/inMemoryCache.ts). * - * `maybeBroadcastWatch` will be set to the `resultCacheMaxSize` option and + * Note: `maybeBroadcastWatch` will be set to the `resultCacheMaxSize` option and * will fall back to this configuration value if the option is not set. * * @defaultValue @@ -192,8 +245,9 @@ export interface CacheSizes { */ "inMemoryCache.maybeBroadcastWatch": number; /** - * Cache size for the `executeSelectionSet` method on [`StoreReader`](../../cache/inmemory/readFromStore.ts). + * Cache size for the `executeSelectionSet` method on [`StoreReader`](https://github.com/apollographql/apollo-client/blob/main/src/cache/inmemory/readFromStore.ts). * + * Note: * `executeSelectionSet` will be set to the `resultCacheMaxSize` option and * will fall back to this configuration value if the option is not set. * @@ -206,8 +260,9 @@ export interface CacheSizes { */ "inMemoryCache.executeSelectionSet": number; /** - * Cache size for the `executeSubSelectedArray` method on [`StoreReader`](../../cache/inmemory/readFromStore.ts). + * Cache size for the `executeSubSelectedArray` method on [`StoreReader`](https://github.com/apollographql/apollo-client/blob/main/src/cache/inmemory/readFromStore.ts). * + * Note: * `executeSubSelectedArray` will be set to the `resultCacheMaxSize` option and * will fall back to this configuration value if the option is not set. *