Skip to content

Commit

Permalink
Add ability to specify custom document transform during manifest gene…
Browse files Browse the repository at this point in the history
…ration (#412)

Apollo Client v3.8 added support for [custom document transforms](https://www.apollographql.com/docs/react/data/document-transforms) that can be used to modify queries before they are sent to the server. This change adds support for this feature during manifest generation to ensure the queries saved to the manifest match what will be sent by the client in a running app.
  • Loading branch information
jerelmiller authored Feb 22, 2024
1 parent 88c8267 commit c43f485
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 7 deletions.
28 changes: 28 additions & 0 deletions .changeset/dirty-masks-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@apollo/generate-persisted-query-manifest": minor
---

Add ability to specify a custom document transform used during manifest generation.

> [!NOTE]
> You must be running Apollo Client 3.8.0 or greater to use this feature.
> [!IMPORTANT]
> This should be the same document transform that is passed to your `ApolloClient` instance, otherwise you risk mismatches in the query output.
```ts
// persisted-query-manifest.config.ts
import { PersistedQueryManifestConfig } from "@apollo/generate-persisted-query-manifest";
import { DocumentTransform } from "@apollo/client/core";

const documentTransform = new DocumentTransform((document) => {
// transform your document
return transformedDocument;
})

const config: PersistedQueryManifestConfig = {
documentTransform,
};

export default config;
```
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions packages/generate-persisted-query-manifest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,25 @@ const config = {
},
};
```

- `documentTransform` - `DocumentTransform`

An `@apollo/client` `DocumentTransform` instance used to transform GraphQL documents before they are saved to the manifest. Use this option if you pass a `documentTransform` option to your Apollo Client instance.

For more information, see the Apollo Client [Document transforms](https://www.apollographql.com/docs/react/data/document-transforms) documentation.

> NOTE: This feature is only available if you use Apollo Client 3.8.0 or greater.
```ts
import { DocumentTransform } from "@apollo/client/core";

const config = {
// Inlined for this example, but ideally this should use the same instance
// that is passed to your Apollo Client instance
documentTransform: new DocumentTransform((document) => {
// ... transform the document

return transformedDocument;
}),
};
```
2 changes: 1 addition & 1 deletion packages/generate-persisted-query-manifest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"vfile-reporter": "^6.0.2"
},
"peerDependencies": {
"@apollo/client": "^3.7.0 || ^3.8.0-alpha",
"@apollo/client": "^3.7.0",
"graphql": "14.x || 15.x || 16.x"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ test("can specify custom document location with config file", async () => {

{
const ymlConfig = `
documents:
documents:
- queries/**/*.graphql
`;

Expand All @@ -690,7 +690,7 @@ module.exports = {
import { PersistedQueryManifestConfig } from '@apollo/generate-persisted-query-manifest';
const config: PersistedQueryManifestOperation = {
documents: ['queries/**/*.graphql']
documents: ['queries/**/*.graphql']
}
export default config;
Expand Down Expand Up @@ -894,7 +894,7 @@ const config: PersistedQueryManifestConfig = {
return Buffer.from(query).toString("base64");
default:
return createDefaultId();
}
}
}
};
Expand Down Expand Up @@ -925,6 +925,71 @@ export default config;
await cleanup();
});

test("can specify custom document transform in config using Apollo Client > 3.8", async () => {
const { cleanup, runCommand, writeFile, readFile, execute } = await setup();
const query = gql`
query GreetingQuery {
user {
id
name @custom
}
}
`;

const expectedQuery = gql`
query GreetingQuery {
user {
id
name
}
}
`;

await writeFile(
"./package.json",
JSON.stringify({
dependencies: {
"@apollo/client": "^3.8.0",
},
}),
);
await execute("npm", "install");
await writeFile("./src/greeting-query.graphql", print(query));
await writeFile(
"./persisted-query-manifest.config.ts",
`
import { PersistedQueryManifestConfig } from '@apollo/generate-persisted-query-manifest';
import { DocumentTransform } from '@apollo/client/core';
import { removeDirectivesFromDocument } from '@apollo/client/utilities';
const documentTransform = new DocumentTransform((document) => {
return removeDirectivesFromDocument([{ name: 'custom' }], document);
});
const config: PersistedQueryManifestConfig = {
documentTransform,
};
export default config;
`,
);

const { code } = await runCommand();
const manifest = await readFile("./persisted-query-manifest.json");

expect(code).toBe(0);
expect(manifest).toBeManifestWithOperations([
{
id: sha256(addTypenameToDocument(expectedQuery)),
name: "GreetingQuery",
body: print(addTypenameToDocument(expectedQuery)),
type: "query",
},
]);

await cleanup();
});

test("errors on anonymous operations", async () => {
const { cleanup, runCommand, writeFile } = await setup();
const query = gql`
Expand Down
47 changes: 46 additions & 1 deletion packages/generate-persisted-query-manifest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import {
InMemoryCache,
Observable,
} from "@apollo/client/core";
import type {
ApolloClientOptions,
// @ts-ignore
DocumentTransform as RealDocumentTransform,
} from "@apollo/client/core";
import { sortTopLevelDefinitions } from "@apollo/persisted-query-lists";
import { gqlPluckFromCodeStringSync } from "@graphql-tools/graphql-tag-pluck";
import globby from "globby";
Expand All @@ -27,6 +32,13 @@ import chalk from "chalk";

type OperationType = "query" | "mutation" | "subscription";

// If the user uses Apollo Client 3.7, `DocumentTransform` won't exist.
// TypeScript will default the value to `any` in this case. We don't want to
// allow this property in this case, so we set the type to `never`.
type DocumentTransform = any extends RealDocumentTransform
? never
: RealDocumentTransform;

interface CreateOperationIdOptions {
operationName: string;
type: OperationType;
Expand All @@ -40,6 +52,34 @@ export interface PersistedQueryManifestConfig {
*/
documents?: string | string[];

/**
* A `DocumentTransform` instance that will be used to transform the GraphQL
* document before it is saved to the manifest.
*
* For more information about document transforms, see the [Document
* transforms](https://www.apollographql.com/docs/react/data/document-transforms)
* documentation page.
*
* IMPORTANT: You must be running `@apollo/client` 3.8.0 or greater to use
* this feature.
*
* @example
* ```ts
* import { DocumentTransform } from "@apollo/client/core";
*
* const config = {
* documentTransform: new DocumentTransform((document) => {
* // ... transform the document
*
* return transformedDocument;
* })
* }
* ```
*
* @since 1.2.0
*/
documentTransform?: DocumentTransform;

/**
* Path where the manifest file will be written.
*/
Expand Down Expand Up @@ -298,10 +338,15 @@ export async function generatePersistedQueryManifest(
...sources.map(({ node }) => node).filter(Boolean),
);
const manifestOperationIds = new Map<string, string>();

const manifestOperations: PersistedQueryManifestOperation[] = [];
const clientConfig: Partial<ApolloClientOptions<any>> = {};

if (config.documentTransform) {
clientConfig.documentTransform = config.documentTransform;
}

const client = new ApolloClient({
...clientConfig,
cache: new InMemoryCache({
fragments,
}),
Expand Down
3 changes: 2 additions & 1 deletion packages/generate-persisted-query-manifest/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"extends": "../../tsconfig.base",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
"outDir": "dist",
"removeComments": false
},
"include": ["src/**/*"],
"exclude": ["**/__tests__"],
Expand Down

0 comments on commit c43f485

Please sign in to comment.