Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/typescript project #773

Merged
merged 15 commits into from
May 24, 2024
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
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"baseBranch": "trunk",
"updateInternalDependencies": "patch",
"privatePackages": { "version": true, "tag": false },
"ignore": ["@10up/wp-nextjs", "@10up/wp-nextjs-ts", "@10up/wp-multisite-nextjs", "@10up/wp-multisite-i18n-nextjs"]
"ignore": ["@10up/wp-nextjs", "@10up/wp-multisite-nextjs", "@10up/wp-multisite-i18n-nextjs"]
}
8 changes: 8 additions & 0 deletions .changeset/short-steaks-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@headstartwp/next": patch
"@headstartwp/core": patch
---

Fix: Improve types for better page props type inference.

It also updates types for data fetching hooks to better reflect the fact that `data` is treated as though it is always there and if users do not check for `loading` or `error` by themselves and there's no preloaded data, a runtime fatal error will be issued instead.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
slug: /getting-started/setting-up-manually
sidebar_position: 1
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Setting up the framework from scratch

The recommended way to get started with the framework is by installing the official starter project. See [Quick Setup](/learn/getting-started/quick-setup/) for more information.
Expand Down Expand Up @@ -72,6 +76,40 @@ module.exports = withHeadstartWPConfig(nextConfig);

Create a custom `_app.js` to wrap the application with `HeadlessApp` component.

<Tabs>
<TabItem value="ts" label="TypeScript">

```ts title=src/pages/_app.tsx
type MyAppProps = {
themeJson: Record<string, unknown>;
fallback: Record<string, unknown>;
};

const MyApp = ({ Component, pageProps }: AppProps<MyAppProps>) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { fallback = {}, themeJson = {}, ...props } = pageProps;

return (
<HeadlessApp
pageProps={pageProps}
settings={{
// instruct the framework to use Next.js link component
// or your own version
linkComponent: Link,
}}
useYoastHtml
>
<Layout>
<Component {...props} />
</Layout>
</HeadlessApp>
);
};
```

</TabItem>
<TabItem value="js" label="JavaScript">

```js title=src/pages/_app.js
import { HeadlessApp } from '@headstartwp/next';
import Link from 'next/link';
Expand All @@ -89,9 +127,11 @@ const MyApp = ({ Component, pageProps }) => {
<HeadlessApp
pageProps={pageProps}
settings={{
// instruct the framework to use Next.js link component or your own version
// instruct the framework to use Next.js link component
// or your own version
linkComponent: Link,
}}
useYoastHtml
>
<Component {...props} />
</HeadlessApp>
Expand All @@ -101,12 +141,41 @@ const MyApp = ({ Component, pageProps }) => {
export default MyApp;
```

</TabItem>
</Tabs>


### Setting up the preview endpoint

The WordPress plugin expects the preview endpoint to be located at `/api/preview`.

To enable support for previews, create a `src/pages/api/preview.js` with the following contents:

<Tabs>
<TabItem value="ts" label="TypeScript">

```js title=src/pages/api/preview.ts
import { previewHandler } from '@headstartwp/next';
import type { NextApiRequest, NextApiResponse } from 'next';

/**
* The Preview endpoint just needs to proxy the default preview handler
*
* @param req Next.js request
* @param res Next.js response
*
* @returns the preview handler
*/
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
return previewHandler(req, res);
}

```

</TabItem>

<TabItem value="js" label="JavaScript">

```js title=src/pages/api/preview.js
import { previewHandler } from '@headstartwp/next';

Expand All @@ -123,6 +192,9 @@ export default async function handler(req, res) {
}
```

</TabItem>
</Tabs>

### Setting up the revalidate endpoint

The framework supports ISR revalidation triggered by WordPress. To enable ISR revalidate, make sure you have the WordPress plugin enabled and activate the option in WordPress settings.
Expand All @@ -131,6 +203,31 @@ The framework supports ISR revalidation triggered by WordPress. To enable ISR re

Then add the `revalidateHandler` to `src/pages/api/revalidate.js`

<Tabs>
<TabItem value="ts" label="TypeScript">

```ts title=src/pages/api/revalidate.ts
import { revalidateHandler } from '@headstartwp/next';
import type { NextApiRequest, NextApiResponse } from 'next';

/**
* The revalidate endpoint just needs to proxy the default revalidate handler
*
* @param req Next.js request
* @param res Next.js response
*
* @returns the revalidate handler
*/
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
return revalidateHandler(req, res);
}

```

</TabItem>

<TabItem value="js" label="JavaScript">

```js title=src/pages/api/revalidate.js
import { revalidateHandler } from '@headstartwp/next';

Expand All @@ -147,12 +244,57 @@ export default async function handler(req, res) {
}
```

</TabItem>
</Tabs>

### Creating your first route

To make sure everything is working as expected create a catch-all route called `pages/[...path].js`. This route will be responsible for rendering single post and pages.

By creating a `[...path].js` route, the framework will automatically detect and extract URL parameters from the `path` argument.

<Tabs>
<TabItem value="ts" label="TypeScript">

```js title=src/pages/[...path].tsx
import type { PostParams } from '@headstartwp/core';
import {
usePost,
fetchHookData,
addHookData,
handleError,
usePosts
} from '@headstartwp/next';
import { BlocksRenderer } from '@headstartwp/core/react';

const params: PostParams = { postType: ['post', 'page' ] };

const SinglePostsPage = () => {
const { loading, error, data } = usePost(params);

if (loading) {
return 'Loading...';
}

if (error) {
return 'error...';
}

return (
<div>
<h1>{data.post.title.rendered}</h1>
<BlocksRenderer html={data.post.content.rendered} />
</div>
);
};

export default SinglePostsPage;
```

</TabItem>

<TabItem value="js" label="JavaScript">

```js title=src/pages/[...path].js
import {
usePost,
Expand Down Expand Up @@ -187,6 +329,10 @@ const SinglePostsPage = () => {
export default SinglePostsPage;
```

</TabItem>

</Tabs>

Then, visit any single post or page, e.g: `http://localhost:3000/hello-world` and you should see both the title and the content of that post/page.

Date URLs will also work: e.g: `http://localhost:3000/2022/10/2/hello-world`
Expand All @@ -197,6 +343,35 @@ With the example above, you might have noticed that the data is only being fetch

Add this to the `pages/[...path].js` file

<Tabs>
<TabItem value="ts" label="TypeScript">

```ts title="src/pages/[...path].tsx"
import type { HeadlessGetStaticProps } from '@headstartwp/next';

export const getStaticProps = (async (context) => {
try {
const settledPromises = await resolveBatch([
{
func: fetchHookData(usePost.fetcher(), context, { params: singleParams }),
},
{ func: fetchHookData(useAppSettings.fetcher(), context) },
]);

return addHookData(settledPromises, { revalidate: 5 * 60 });
} catch (e) {
return handleError(e, context);
}
}) satisfies HeadlessGetStaticProps;

// `satisfies` allow TS to infer the correct types for context as well as makes it
// possible to correctly infer the page props
```

</TabItem>

<TabItem value="js" label="JavaScript">

```js title="src/pages/[...path].js"
// or export async function getServerSideProps(context)
export async function getStaticProps(context) {
Expand All @@ -211,4 +386,7 @@ export async function getStaticProps(context) {
}
```

</TabItem>
</Tabs>

Then refresh the page and voilá! Data is now being fetched on the server.
Loading
Loading