Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"cSpell.words": [
"codegen",
"combobox",
"Diátaxis",
"faustjs",
Expand Down
12 changes: 12 additions & 0 deletions src/pages/docs/explanation/migrating-to-typescript/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const metadata = {
title: "Migrating to TypeScript",
};

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.

For Faust, see the [TypeScript Reference Doc](/docs/reference/typescript).

## Further Reading

- [TypeScript Reference](/docs/reference/typescript)
- [Typing GraphQL Queries with GraphQL Codegen](/docs/how-to/generate-types-with-graphql-codegen)
9 changes: 6 additions & 3 deletions src/pages/docs/how-to/basic-setup/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export default setConfig({

### Create Faust API route

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:
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:

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

### Update `_app.js` file

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

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

## Setup the Template Hierarchy
## Set up the Template Hierarchy

### Generate types

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

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

> [!IMPORTANT] Important
> 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).

### Add a template

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.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
142 changes: 142 additions & 0 deletions src/pages/docs/how-to/generate-types-with-graphql-codegen/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
export const metadata = {
title: "Generate types with GraphQL Codegen",
};

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).

> [!TIP]
> 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.

## 0. Prerequisites

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:

```bash
npm install -D typescript @graphql-codegen/cli
```

## 1. Add Codegen Configuration

In the root of your project, create a configuration file named `codegen.ts`

```ts title="codegen.ts"
import { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
schema: "https://faustexample.wpengine.com/graphql",
documents: ["src/**/*.{tsx,ts}"],
generates: {
"./src/__generated__/": {
preset: "client",
plugins: [],
presetConfig: {
gqlTagName: "gql",
},
},
},
ignoreNoDocuments: true,
};

export default config;
```

## 2. Add Codegen Script

Next, update your package.json to add a script for running the code generator:

```json title="package.json"
{
"scripts": {
"generate:types": "graphql-codegen"
}
}
```

Now you can run:

```bash
npm run generate:types
```

This command will scan your `src/` folder for any GraphQL queries or fragments, then generate TypeScript types in `src/__generated__/graphql.ts`.

> [!IMPORTANT] Important
> 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).

## 3. Using Generated Types

### A. Typing Templates

After Codegen runs, you'll see auto-generated types in graphql.ts. For example:

```ts title="src/__generated__/graphql.ts"
export type GetPostQueryVariables = Exact<{
databaseId: Scalars["ID"];
asPreview?: InputMaybe<Scalars["Boolean"]>;
}>;

export type GetPostQuery = {
// ...
};
```

You can use these types with the `FaustTemplate` helper in your WordPress templates:

```tsx title="wp-templates/single.tsx"
import { gql } from "../__generated__";
import { GetPostQuery } from "../__generated__/graphql";
import { FaustTemplate } from "@faustwp/core";

const Component: FaustTemplate<GetPostQuery> = (props) => {
// `props.data` and other fields are now typed!
return <div>{props?.data?.post?.title}</div>;
};

export const pageQuery = gql(/* GraphQL */ `
query GetPost($databaseId: ID!, $asPreview: Boolean) {
...
}
`);
```

Then you can inspect all the types in the `props` parameters as you type:

![](./images/ts-image-one.png)

All the data from the query results will be properly typed based on the introspected schema:

![](./images/ts-image-two.png)

### B. Typing Block Components

If you create blocks with `@faustwp/blocks`, you can use the WordPressBlock type to add strong typing to those components:

```tsx title="wp-blocks/CoreParagraph.tsx"
import { gql } from "../__generated__";
import { WordPressBlock } from "@faustwp/blocks";
import { CoreParagraphFragmentFragment } from "../__generated__/graphql";

const CoreParagraph: WordPressBlock<CoreParagraphFragmentFragment> = (
props,
) => {
return <p>{props.attributes?.content}</p>;
};

export const fragments = {
entry: gql(`
fragment CoreParagraphFragment on CoreParagraph {
attributes {
content
}
}
`),
key: "CoreParagraphFragment",
};
```

By passing in `CoreParagraphFragmentFragment` to WordPressBlock, TypeScript enforces that props only contains fields you've declared in the GraphQL fragment.

## Further Reading

- [Migrating to TypeScript](/docs/explanation/migrating-to-typescript)
- [TypeScript Reference](/docs/reference/typescript)
9 changes: 8 additions & 1 deletion src/pages/docs/nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@
"title": "Basic Setup",
"route": "/docs/how-to/basic-setup/"
},

{
"title": "Generate types with GraphQL Codegen",
"route": "/docs/how-to/generate-types-with-graphql-codegen/"
},
{
"title": "Template Hierarchy",
"route": "/docs/how-to/template-hierarchy/"
},
{
"title": "Rendering Blocks",
"route": "/docs/how-to/rendering-blocks/"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions src/pages/docs/reference/typescript/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
export const metadata = {
title: "TypeScript",
};

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.

## Typing Faust Components

- `FaustTemplate` for WP Template pages.
- `WordPressBlock` for block components.
- `GetStaticProps`, `GetServerSideProps`, and `GetStaticPaths` from Next.js for data-fetching methods.
- `FaustHooks` for hooking into the Faust plugin system.

Here's a quick example using `[...wordpressNode].tsx`:

```tsx title="pages/[...wordpressNode].tsx"
import { getWordPressProps, WordPressTemplate } from "@faustwp/core";
import { GetStaticPaths, GetStaticProps } from "next";

export type WordPressTemplateProps = Parameters<typeof WordPressTemplate>[0];

export default function Page(props: WordPressTemplateProps) {
return <WordPressTemplate {...props} />;
}

export const getStaticProps: GetStaticProps = (ctx) => {
return getWordPressProps({ ctx });
};

export const getStaticPaths: GetStaticPaths = () => {
return {
paths: [],
fallback: "blocking",
};
};
```

## Typing Faust Plugins

When creating Faust plugins, you can use the `FaustHooks` type to get autocompletion and type-safety for the hooks system:

```ts title="plugins/ProjectTemplatePlugin.ts"
import { FaustHooks, FaustPlugin } from "@faustwp/core";

export class ProjectTemplatePlugin implements FaustPlugin {
constructor() {}

apply(hooks: FaustHooks) {
hooks.addFilter("possibleTemplatesList", "faust", (templates, data) => {
if (data?.seedNode?.__typename === "Project") {
return Array.from(new Set(["project", ...templates]));
}
return templates;
});
}
}
```

Because `FaustHooks` knows about available filters and hooks, TypeScript will automatically guide you on what the callback signatures should look like.

![](./images/typescript-fausthooks-type.png)

## Further Reading

- [Migrating to TypeScript](/docs/explanation/migrating-to-typescript)
- [Typing GraphQL Queries with GraphQL Codegen](/docs/how-to/generate-types-with-graphql-codegen)
Loading