diff --git a/.api-reports/api-report-react.md b/.api-reports/api-report-react.md index 9730ae3bc79..65a4bbe7d1f 100644 --- a/.api-reports/api-report-react.md +++ b/.api-reports/api-report-react.md @@ -1432,6 +1432,12 @@ type OperationVariables = Record; // @public (undocumented) export function parser(document: DocumentNode): IDocumentDefinition; +// @public (undocumented) +export namespace parser { + var // (undocumented) + resetCache: () => void; +} + // @public (undocumented) type Path = ReadonlyArray; diff --git a/.api-reports/api-report-react_parser.md b/.api-reports/api-report-react_parser.md index 96d961506af..9dd7eab4a8b 100644 --- a/.api-reports/api-report-react_parser.md +++ b/.api-reports/api-report-react_parser.md @@ -34,6 +34,12 @@ export function operationName(type: DocumentType_2): string; // @public (undocumented) export function parser(document: DocumentNode): IDocumentDefinition; +// @public (undocumented) +export namespace parser { + var // (undocumented) + resetCache: () => void; +} + // @public (undocumented) export function verifyDocumentType(document: DocumentNode, type: DocumentType_2): void; diff --git a/.api-reports/api-report.md b/.api-reports/api-report.md index ae6e27d72e9..9e336a0c50a 100644 --- a/.api-reports/api-report.md +++ b/.api-reports/api-report.md @@ -1931,6 +1931,12 @@ export function parseAndCheckHttpResponse(operations: Operation | Operation[]): // @public (undocumented) export function parser(document: DocumentNode): IDocumentDefinition; +// @public (undocumented) +export namespace parser { + var // (undocumented) + resetCache: () => void; +} + // @public (undocumented) export type Path = ReadonlyArray; diff --git a/.changeset/cold-llamas-turn.md b/.changeset/cold-llamas-turn.md new file mode 100644 index 00000000000..a3f1e0099df --- /dev/null +++ b/.changeset/cold-llamas-turn.md @@ -0,0 +1,8 @@ +--- +"@apollo/client": patch +--- + +`parse` function: improve memory management +* use LRU `WeakCache` instead of `Map` to keep a limited number of parsed results +* cache is initiated lazily, only when needed +* expose `parse.resetCache()` method diff --git a/.size-limits.json b/.size-limits.json index d5dd8296590..ee06be421b2 100644 --- a/.size-limits.json +++ b/.size-limits.json @@ -1,4 +1,4 @@ { - "dist/apollo-client.min.cjs": 38603, + "dist/apollo-client.min.cjs": 38625, "import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32203 } diff --git a/src/react/parser/index.ts b/src/react/parser/index.ts index 984b491142f..cbaa8f69612 100644 --- a/src/react/parser/index.ts +++ b/src/react/parser/index.ts @@ -1,3 +1,4 @@ +import { WeakCache } from "@wry/caches"; import { invariant } from "../../utilities/globals/index.js"; import type { @@ -19,7 +20,16 @@ export interface IDocumentDefinition { variables: ReadonlyArray; } -const cache = new Map(); +let cache: + | undefined + | WeakCache< + DocumentNode, + { + name: string; + type: DocumentType; + variables: readonly VariableDefinitionNode[]; + } + >; export function operationName(type: DocumentType) { let name; @@ -39,6 +49,10 @@ export function operationName(type: DocumentType) { // This parser is mostly used to safety check incoming documents. export function parser(document: DocumentNode): IDocumentDefinition { + if (!cache) { + cache = + new WeakCache(/** TODO: decide on a maximum size (will do all max sizes in a combined separate PR) */); + } const cached = cache.get(document); if (cached) return cached; @@ -131,6 +145,10 @@ export function parser(document: DocumentNode): IDocumentDefinition { return payload; } +parser.resetCache = () => { + cache = undefined; +}; + export function verifyDocumentType(document: DocumentNode, type: DocumentType) { const operation = parser(document); const requiredOperationName = operationName(type);