https://github.com/wpengine/faustjs/discussions/515#discussioncomment-1411394
そこで、GQtyClient
のinlineResolved
という関数を使えばいいそうです。
mkdir src/utils
touch src/utils/game.ts
src/utils/game.ts
import { client, GameIdType } from '@/client';
import { getFields, getArrayFields } from 'gqty';
const checkGameExistsBySlug = async (slug: string) => {
const { inlineResolved, query } = client.client;
const game = await inlineResolved(() => {
return getFields(
query.game({
id: slug,
idType: GameIdType.SLUG,
}),
'id'
);
});
return game !== null;
};
const getAllGameSlugParams = async (paramName: string) => {
const games = await client.client.inlineResolved(() => {
return getArrayFields(client.client.query.games()?.nodes, 'slug');
});
return games
? games.map((game) => {
return {
params: {
[paramName]: game.slug,
},
};
})
: [];
};
export { checkGameExistsBySlug, getAllGameSlugParams };
これらのユーティリティを、カスタムタクソノミーがルーティングに絡んでくる場所で使います。
inlineResolved
のコールバック関数でgetFields
またはgetArrayFields
を使うことで、データの実体を取得します。これらを用意することでやっと、適切な404判定やパスの生成ができます。
DIR=src/pages/games/[gameSlug]
mkdir -p $DIR && touch $DIR/index.tsx
src/pages/games/[gameSlug]/index.tsx
import { getNextStaticProps } from '@faustjs/next';
import { GetStaticPropsContext } from 'next';
import { useRouter } from 'next/router';
import {
client,
GameIdType,
RelationEnum,
RootQueryToPostConnectionWhereArgsTaxQueryField,
RootQueryToPostConnectionWhereArgsTaxQueryOperator,
TaxonomyEnum,
} from 'client';
import { checkGameExistsBySlug, getAllGameSlugParams } from '@/utils/game';
const POSTS_PER_PAGE = 6;
export default function Page() {
const { useQuery, usePosts } = client;
const { query = {} } = useRouter();
const { gameSlug, paginationTerm, gameCursor } = query;
const game = useQuery().game({ id: gameSlug.toString(), idType: GameIdType.SLUG });
const isBefore = paginationTerm === 'before';
const posts = usePosts({
after: !isBefore ? (gameCursor as string) : undefined,
before: isBefore ? (gameCursor as string) : undefined,
first: !isBefore ? POSTS_PER_PAGE : undefined,
last: isBefore ? POSTS_PER_PAGE : undefined,
where: {
taxQuery: {
relation: RelationEnum.AND,
taxArray: [
{
terms: [game?.slug],
taxonomy: TaxonomyEnum.GAME,
operator: RootQueryToPostConnectionWhereArgsTaxQueryOperator.IN,
field: RootQueryToPostConnectionWhereArgsTaxQueryField.SLUG,
},
],
},
},
});
return (
);
}
export async function getStaticProps(context: GetStaticPropsContext) {
const notFound = !(await checkGameExistsBySlug(context.params.gameSlug.toString()));
return getNextStaticProps(context, {
Page,
client,
notFound,
});
}
export async function getStaticPaths() {
const paths = await getAllGameSlugParams('gameSlug');
return {
paths,
fallback: 'blocking',
};
}
なお、クライアント側では普通にusePosts
を使い、taxQuery
で絞り込みます。これは2022年4月30日現在、wp-graphql-tax-queryプラグインがないと使えないため注意して下さい。
カーソルを使ったページネーションについては公式のexampleをご参照下さい。
ページネーション
DIR=$DIR/[paginationTerm]
mkdir -p $DIR && touch "$DIR/[gameCursor].tsx"
src/pages/games/[gameSlug]/[paginationTerm]/[gameCursor].tsx
import { GetStaticPropsContext } from 'next';
import Page from '@/pages/games/[gameSlug]';
import { getNextStaticProps } from '@faustjs/next';
import { client } from 'client';
import { checkGameExistsBySlug } from '@/utils/game';
export default Page;
export async function getStaticProps(context: GetStaticPropsContext) {
const { paginationTerm, gameSlug } = context.params;
const notFound = !(paginationTerm === 'after' || paginationTerm === 'before') || !(await checkGameExistsBySlug(gameSlug.toString()));
return getNextStaticProps(context, {
Page,
client,
notFound,
});
}
export function getStaticPaths() {
return {
paths: [],
fallback: 'blocking',
};
}
これはFaust.jsのチュートリアルと同じですが、独自にゲームの存在判定を追加しています。 これがないと存在しないスラッグでも404になりません。
なお、ここではパスを生成しません。随時変化するカーソルをビルド時に使う意義は薄いでしょう。
├ ● /games/[gameSlug] (ISR: 900 Seconds) (9804 ms) 1.76 kB 184 kB
├ ├ /games/minecraft-dungeons (1532 ms)
├ ├ /games/minecraft-console (1519 ms)
├ ├ /games/minecraft-je (1427 ms)
├ ├ /games/hytale (1330 ms)
├ └ /games/minecraft (1225 ms)
上記の実装だと、こんな感じでパスが生成されます。
以上、Faust.jsでカスタムタクソノミーを扱う手順でした。GQtyの情報がなさすぎてつらい。