Skip to content

Commit 35401b5

Browse files
authored
Merge pull request #231 from wpengine/re-re-ts
Re re ts
2 parents d99f8e6 + 6e568f9 commit 35401b5

File tree

9 files changed

+235
-4
lines changed

9 files changed

+235
-4
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"cSpell.words": [
3+
"codegen",
34
"combobox",
45
"Diátaxis",
56
"faustjs",
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export const metadata = {
2+
title: "Migrating to TypeScript",
3+
};
4+
5+
If you have existing Next.js pages that you want to migrate to TypeScript, you can follow the [official TypeScript Docs](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html) for general TypeScript migration tips.
6+
7+
For Faust, see the [TypeScript Reference Doc](/docs/reference/typescript).
8+
9+
## Further Reading
10+
11+
- [TypeScript Reference](/docs/reference/typescript)
12+
- [Typing GraphQL Queries with GraphQL Codegen](/docs/how-to/generate-types-with-graphql-codegen)

src/pages/docs/how-to/basic-setup/index.mdx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export default setConfig({
6161

6262
### Create Faust API route
6363

64-
Create an API route for Faust.js to use. You can do this by creating a file in `pages/api/faust/[[...route]].`js, with the following code:
64+
Create an API route for Faust.js to use. You can do this by creating a file in `pages/api/faust/[[...route]].js`, with the following code:
6565

6666
```js title="pages/api/faust/[[...route]].js"
6767
import "../../../faust.config";
@@ -71,7 +71,7 @@ export { apiRouter as default } from "@faustwp/core";
7171

7272
### Update `_app.js` file
7373

74-
Once the API router is set up, head to `pages/_api.js` and paste this code into the file:
74+
Once the API router is set up, head to `pages/_app.js` and add this code to the file:
7575

7676
```js title="pages/_app.js"
7777
import { useRouter } from "next/router";
@@ -89,7 +89,7 @@ export default function MyApp({ Component, pageProps }) {
8989
}
9090
```
9191

92-
## Setup the Template Hierarchy
92+
## Set up the Template Hierarchy
9393

9494
### Generate types
9595

@@ -109,6 +109,9 @@ Add the following generate script to your Next.js project's `package.json` file,
109109

110110
Run `npm run generate` on the command line. Confirm that a possibleTypes.json has been generated in the root of your project.
111111

112+
> [!IMPORTANT] Important
113+
> Be sure to enable WPGraphQL introspection before running the `npm run generate` command since it is [disabled by default](https://www.wpgraphql.com/docs/security#introspection-disabled-by-default).
114+
112115
### Add a template
113116

114117
Create a new `wp-templates` folder in the root of your project. This is where your template files will be stored. We'll start by adding a template for rendering single blog posts.
71.5 KB
Loading
237 KB
Loading
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
export const metadata = {
2+
title: "Generate types with GraphQL Codegen",
3+
};
4+
5+
Faust.js provides built-in TypeScript support, including types for Templates, Blocks, and more. This guide will show you how to generate fully typed definitions for your custom GraphQL queries and fragments using [GraphQL Code Generator](https://the-guild.dev/graphql/codegen).
6+
7+
> [!TIP]
8+
> If you're looking to generate [Apollo-specific fragment matching](https://www.apollographql.com/docs/react/data/fragments#using-fragments-with-unions-and-interfaces) metadata (i.e. `possibleTypes`), see the `faust generatePossibleTypes` command. However, that command does **not** produce TypeScript definitions for your queries. For typing your queries in Faust, continue reading below.
9+
10+
## 0. Prerequisites
11+
12+
If you haven't already, follow the [Basic Setup](/docs/how-to/basic-setup/) steps to get Faust.js configured. Once your project is set up, add `@graphql-codegen/cli` to your project:
13+
14+
```bash
15+
npm install -D typescript @graphql-codegen/cli
16+
```
17+
18+
## 1. Add Codegen Configuration
19+
20+
In the root of your project, create a configuration file named `codegen.ts`
21+
22+
```ts title="codegen.ts"
23+
import { CodegenConfig } from "@graphql-codegen/cli";
24+
25+
const config: CodegenConfig = {
26+
schema: "https://faustexample.wpengine.com/graphql",
27+
documents: ["src/**/*.{tsx,ts}"],
28+
generates: {
29+
"./src/__generated__/": {
30+
preset: "client",
31+
plugins: [],
32+
presetConfig: {
33+
gqlTagName: "gql",
34+
},
35+
},
36+
},
37+
ignoreNoDocuments: true,
38+
};
39+
40+
export default config;
41+
```
42+
43+
## 2. Add Codegen Script
44+
45+
Next, update your package.json to add a script for running the code generator:
46+
47+
```json title="package.json"
48+
{
49+
"scripts": {
50+
"generate:types": "graphql-codegen"
51+
}
52+
}
53+
```
54+
55+
Now you can run:
56+
57+
```bash
58+
npm run generate:types
59+
```
60+
61+
This command will scan your `src/` folder for any GraphQL queries or fragments, then generate TypeScript types in `src/__generated__/graphql.ts`.
62+
63+
> [!IMPORTANT] Important
64+
> Be sure to enable WPGraphQL introspection before running the `npm run generate` command since it is [disabled by default](https://www.wpgraphql.com/docs/security#introspection-disabled-by-default).
65+
66+
## 3. Using Generated Types
67+
68+
### A. Typing Templates
69+
70+
After Codegen runs, you'll see auto-generated types in graphql.ts. For example:
71+
72+
```ts title="src/__generated__/graphql.ts"
73+
export type GetPostQueryVariables = Exact<{
74+
databaseId: Scalars["ID"];
75+
asPreview?: InputMaybe<Scalars["Boolean"]>;
76+
}>;
77+
78+
export type GetPostQuery = {
79+
// ...
80+
};
81+
```
82+
83+
You can use these types with the `FaustTemplate` helper in your WordPress templates:
84+
85+
```tsx title="wp-templates/single.tsx"
86+
import { gql } from "../__generated__";
87+
import { GetPostQuery } from "../__generated__/graphql";
88+
import { FaustTemplate } from "@faustwp/core";
89+
90+
const Component: FaustTemplate<GetPostQuery> = (props) => {
91+
// `props.data` and other fields are now typed!
92+
return <div>{props?.data?.post?.title}</div>;
93+
};
94+
95+
export const pageQuery = gql(/* GraphQL */ `
96+
query GetPost($databaseId: ID!, $asPreview: Boolean) {
97+
...
98+
}
99+
`);
100+
```
101+
102+
Then you can inspect all the types in the `props` parameters as you type:
103+
104+
![](./images/ts-image-one.png)
105+
106+
All the data from the query results will be properly typed based on the introspected schema:
107+
108+
![](./images/ts-image-two.png)
109+
110+
### B. Typing Block Components
111+
112+
If you create blocks with `@faustwp/blocks`, you can use the WordPressBlock type to add strong typing to those components:
113+
114+
```tsx title="wp-blocks/CoreParagraph.tsx"
115+
import { gql } from "../__generated__";
116+
import { WordPressBlock } from "@faustwp/blocks";
117+
import { CoreParagraphFragmentFragment } from "../__generated__/graphql";
118+
119+
const CoreParagraph: WordPressBlock<CoreParagraphFragmentFragment> = (
120+
props,
121+
) => {
122+
return <p>{props.attributes?.content}</p>;
123+
};
124+
125+
export const fragments = {
126+
entry: gql(`
127+
fragment CoreParagraphFragment on CoreParagraph {
128+
attributes {
129+
content
130+
}
131+
}
132+
`),
133+
key: "CoreParagraphFragment",
134+
};
135+
```
136+
137+
By passing in `CoreParagraphFragmentFragment` to WordPressBlock, TypeScript enforces that props only contains fields you've declared in the GraphQL fragment.
138+
139+
## Further Reading
140+
141+
- [Migrating to TypeScript](/docs/explanation/migrating-to-typescript)
142+
- [TypeScript Reference](/docs/reference/typescript)

src/pages/docs/nav.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@
1111
"title": "Basic Setup",
1212
"route": "/docs/how-to/basic-setup/"
1313
},
14-
14+
{
15+
"title": "Generate types with GraphQL Codegen",
16+
"route": "/docs/how-to/generate-types-with-graphql-codegen/"
17+
},
18+
{
19+
"title": "Template Hierarchy",
20+
"route": "/docs/how-to/template-hierarchy/"
21+
},
1522
{
1623
"title": "Rendering Blocks",
1724
"route": "/docs/how-to/rendering-blocks/"
168 KB
Loading
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
export const metadata = {
2+
title: "TypeScript",
3+
};
4+
5+
Faust has built-in TypeScript support, which means you can use TypeScript to type your Faust components, hooks, and plugins. This may not be exhaustive but should show you common patterns for typing your Faust code.
6+
7+
## Typing Faust Components
8+
9+
- `FaustTemplate` for WP Template pages.
10+
- `WordPressBlock` for block components.
11+
- `GetStaticProps`, `GetServerSideProps`, and `GetStaticPaths` from Next.js for data-fetching methods.
12+
- `FaustHooks` for hooking into the Faust plugin system.
13+
14+
Here's a quick example using `[...wordpressNode].tsx`:
15+
16+
```tsx title="pages/[...wordpressNode].tsx"
17+
import { getWordPressProps, WordPressTemplate } from "@faustwp/core";
18+
import { GetStaticPaths, GetStaticProps } from "next";
19+
20+
export type WordPressTemplateProps = Parameters<typeof WordPressTemplate>[0];
21+
22+
export default function Page(props: WordPressTemplateProps) {
23+
return <WordPressTemplate {...props} />;
24+
}
25+
26+
export const getStaticProps: GetStaticProps = (ctx) => {
27+
return getWordPressProps({ ctx });
28+
};
29+
30+
export const getStaticPaths: GetStaticPaths = () => {
31+
return {
32+
paths: [],
33+
fallback: "blocking",
34+
};
35+
};
36+
```
37+
38+
## Typing Faust Plugins
39+
40+
When creating Faust plugins, you can use the `FaustHooks` type to get autocompletion and type-safety for the hooks system:
41+
42+
```ts title="plugins/ProjectTemplatePlugin.ts"
43+
import { FaustHooks, FaustPlugin } from "@faustwp/core";
44+
45+
export class ProjectTemplatePlugin implements FaustPlugin {
46+
constructor() {}
47+
48+
apply(hooks: FaustHooks) {
49+
hooks.addFilter("possibleTemplatesList", "faust", (templates, data) => {
50+
if (data?.seedNode?.__typename === "Project") {
51+
return Array.from(new Set(["project", ...templates]));
52+
}
53+
return templates;
54+
});
55+
}
56+
}
57+
```
58+
59+
Because `FaustHooks` knows about available filters and hooks, TypeScript will automatically guide you on what the callback signatures should look like.
60+
61+
![](./images/typescript-fausthooks-type.png)
62+
63+
## Further Reading
64+
65+
- [Migrating to TypeScript](/docs/explanation/migrating-to-typescript)
66+
- [Typing GraphQL Queries with GraphQL Codegen](/docs/how-to/generate-types-with-graphql-codegen)

0 commit comments

Comments
 (0)