-
Notifications
You must be signed in to change notification settings - Fork 136
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
[PROPOSAL] Next.js Templating #235
Comments
I think you're right on this one. I believe in Next.js the To expand on
The other thing we need to think about related to this: import React from 'react';
import { GetStaticPropsContext } from 'next';
import { getApolloClient, getPosts } from '@wpengine/headless-core';
export default function Page({ posts }) {
return <Posts posts={posts} />;
}
export async function getStaticProps(context: GetStaticPropsContext) {
const client = getApolloClient(context);
const posts = await getPosts(client);
return {
revalidate: 1,
props: {
posts,
},
};
} A note on the code ☝️, there is no opportunity there for us to put the Apollo cache on props or otherwise return a 404. Perhaps we could have something like the following to take care of the Apollo cache: import React from 'react';
import { GetStaticPropsContext } from 'next';
import { getApolloClient, addApolloClientCacheToProps, getPosts } from '@wpengine/headless-core';
export default function Page({ posts }) {
return <Posts posts={posts} />;
}
export async function getStaticProps(context: GetStaticPropsContext) {
const client = getApolloClient(context);
const posts = await getPosts(client);
const props = addApolloClientCacheToProps({
posts,
});
return {
revalidate: 1,
props,
};
} With import React from 'react';
import {
getNextStaticProps,
usePost,
} from '@wpengine/headless-next';
import { GetStaticPropsContext } from 'next';
import { getApolloClient, getPosts } from '@wpengine/headless-core';
export default function Page() {
const posts = usePosts();
return <Posts posts={posts} />;
}
export async function getStaticProps(context: GetStaticPropsContext) {
const client = getApolloClient(context);
await getPosts(client);
return getNextStaticProps(context);
} The second example seems a little cleaner and supports optional client-side requests where necessary as well as the ability to add in SSG/SSR without having to reconfigure your application. However, the second example does involve a little bit of indirection because the app developer has to understand that the framework is going to cache the Apollo client and restore it with the import React from 'react';
import {
getNextStaticProps,
usePost,
} from '@wpengine/headless-next';
import Head from 'next/head';
import { GetStaticPropsContext } from 'next';
import { getApolloClient, getPosts } from '@wpengine/headless-core';
export default function Page({ title }) {
const posts = usePosts();
return (<>
<Head>
<title>{title}</title>
</Head>
<Posts posts={posts} />
</>);
}
export async function getStaticProps(context: GetStaticPropsContext) {
const client = getApolloClient(context);
await getPosts(client);
const result = getNextStaticProps(context);
result.props.title = 'Posts'; // will break on a 404
return result;
} A better way to do the above logic might be: import React from 'react';
import {
getNextStaticProps,
usePost,
} from '@wpengine/headless-next';
import Head from 'next/head';
import { GetStaticPropsContext } from 'next';
import { getApolloClient, getPosts } from '@wpengine/headless-core';
export default function Page({ title }) {
const posts = usePosts();
return (<>
<Head>
<title>{title}</title>
</Head>
<Posts posts={posts} />
</>);
}
export async function getStaticProps(context: GetStaticPropsContext) {
const client = getApolloClient(context);
await getPosts(client);
return getNextStaticProps(context, {
props: {
title: 'Posts',
}
});
} The code above would still support us returning a |
Intuition says to return the props from For 404s, I think we should default to handling them but allow a away to opt-out. |
Doing all of this (apollo client cache, 404 handling, prop passing) would require some interface similar to above, but could end with code similar to this: import React from 'react';
import {
getNextStaticProps,
usePost,
} from '@wpengine/headless-next';
import Head from 'next/head';
import { GetStaticPropsContext } from 'next';
import { getApolloClient, getPosts } from '@wpengine/headless-core';
export default function Page({ title, posts }) {
// Not needed, but could also work if you want to do it this way
// const posts = usePosts();
return (<>
<Head>
<title>{title}</title>
</Head>
<Posts posts={posts} />
</>);
}
export async function getStaticProps(context: GetStaticPropsContext) {
const client = getApolloClient(context);
const posts = await getPosts(client);
// We probably want to avoid combining the handle404 configuration with the GetStaticPropsResult to extend and return.
// Next yells at you when you have invalid properties.
return getNextStaticProps(context, {
handle404: false,
}, {
props: {
title: 'Posts',
posts,
}
});
} The 404 handling is tricky since the only way we know is based on the |
Agreed on the 404. We need to think that through a bit more, but I like this example better. It looks more like Next. I don't want you to have to reconcile between Next docs and ours. You should be able to follow most of Next's conventions without incompatibilities in what the framework expects. |
Another consideration if we are going to follow Next's conventions of pages/routing, is how we will infer the URL from In the case of a nested route, // pages/category/[...categorySlug].tsx
export default function Page() {
...
}
export async function getStaticProps(context: GetStaticPropsContext) {
/**
* the expected URL would be "/category/uncategorized".
* params does not indicate the "category" path part.
*/
console.log(context?.params) <- "{ categorySlug: [ 'uncategorized' ] }"
} We may have to infer the URL based on a combination of |
NOTE: Good point, with
I think the above works, and we would look for a // /preview/post?p=197&preview=true
params = {
postPreview: [],
};
// /preview/page?page_id=3&preview=true&p=3
params = {
pagePreview: [],
};
// /posts/hello-world
params = {
post: 'hello-world',
};
// /category/uncategorized
params = {
category: 'uncategorized',
};
// /about
params = {
page: 'about',
pageUri: [],
};
// /pricing/startup
params = {
page: 'pricing',
pageUri: ['startup']
}; There is another possibility for someone to want to have both posts and pages under the root URL. So you might have
This would be a more difficult case to target, an I'm not sure how often it comes up. We could certainly use |
@wjohnsto I figured something like that was the case. I played around with it a little, and it looks like it may be possible, the With that being said, your convention works much better, particularity around the structure of I do think that the posts and pages being under the root URL will come up often. In fact, this happened yesterday while I was building a POC using this new proposal. I think this is just something that we'll have to provide a guide for. |
I think if you want to use the root URL-based page and post routes then you will need to use our // pages/[[...postOrPageUri]].tsx
import React from 'react';
import {
getNextStaticProps,
} from '@wpengine/headless-next';
import { GetStaticPropsContext } from 'next';
import { getApolloClient, getPost, getPage, getUriInfo } from '@wpengine/headless-core';
import { Post, Page } from '../components';
export default function PostPage({ post, page }) {
return (<>
{ post && <Post post={post} /> }
{ page && <Page page={page} /> }
</>);
}
export async function getStaticProps(context: GetStaticPropsContext) {
const client = getApolloClient(context);
const uriInfo = await getUriInfo(client, Array.from(context?.params?.postOrPage).join('/'));
let post: WPGraphQL.Post | null = null;
let page: WPGraphQL.Page | null = null;
if (uriInfo.isPage) {
page = await getPage(client);
} else {
post = await getPost(client);
}
// We probably want to avoid combining the handle404 configuration with the GetStaticPropsResult to extend and return.
// Next yells at you when you have invalid properties.
return getNextStaticProps(context, {
props: {
post,
page,
}
});
} |
Adding this feature here as well to keep track of it. We may have users that need multi-page posts. I don't think this functionality is very common, but it may come up. In this case, we could have a guide to support this. To achieve this we would have to alter the
With // /posts/hello-world
params = {
post: 'hello-world',
};
// /posts/hello-world/page/2
params = {
post: 'hello-world',
pageNumber: '2'
}; |
This was resolved in #270 |
NOTE: This is still a work in progress, feedback welcome.
Currently,
@wpengine/headless
provides templating functionality for use in Next.js. This includes the templates inwp-templates/
,getNextStaticProps()
,getNextStaticPaths()
, etc.With the improvements in #232, it will become much easier to query and fetch data.
With these improvements, we may want to consider leveraging the native Next.js page routing system, where the user would implement the data fetching functionality and
getStaticProps
/getStaticPaths
themselves.An example Next.js app using this format will look like:
The text was updated successfully, but these errors were encountered: