diff --git a/next-sitemap.config.cjs b/next-sitemap.config.cjs index fc711b6..2dffdc0 100644 --- a/next-sitemap.config.cjs +++ b/next-sitemap.config.cjs @@ -1,13 +1,15 @@ const fs = require("fs"); const fm = require("front-matter"); +const siteUrl = process.env.SITE_URL || "https://www.aaronjy.me"; /** @type {import('next-sitemap').IConfig} */ module.exports = { - siteUrl: process.env.SITE_URL || "https://www.aaronjy.me", + siteUrl, changefreq: "weekly", generateRobotsTxt: true, autoLastmod: false, generateIndexSitemap: false, + exclude: ["/server-sitemap-index.xml"], // <= exclude here robotsTxtOptions: { policies: [ { @@ -15,30 +17,25 @@ module.exports = { allow: "/", }, ], + additionalSitemaps: [ + `${siteUrl}/server-sitemap-index.xml`, // <==== Add here + ], }, - // transform: async (config, path) => { - // const metadata = { - // loc: path - // } + transform: async (config, path) => { + const metadata = { + loc: path, + }; - // if (isHomepage(path)) { - // metadata.priority = 1 - // } else if (isBasePage(path)) { - // metadata.priority = 0.8 - // } else { - // if (isArticle(path)) { - // metadata.priority = 0.6 - // const attributes = getArticleAttibutes(`content${path}.md`) - // if (!attributes) { return null } + if (isHomepage(path)) { + metadata.priority = 1; + } else if (isBasePage(path)) { + metadata.priority = 0.8; + } else if (isArticle(path)) { + metadata.priority = 0.6; + } - // metadata.lastmod = attributes.moddate ?? attributes.pubdate ?? null - - // console.log('Calculated sitemap dates for article', path) - // } - // } - - // return metadata - // } + return metadata; + }, }; function isHomepage(path) { @@ -50,20 +47,5 @@ function isBasePage(path) { } function isArticle(path) { - return path.startsWith("/writing/"); -} - -function getArticleAttibutes(path) { - const fileContents = fs.readFileSync(path, { - encoding: "utf-8", - }); - - // @ts-ignore - const { attributes } = fm(fileContents); - - return { - ...attributes, - pubdate: attributes.pubdate?.toUTCString() ?? null, - moddate: attributes.moddate?.toUTCString() ?? null, - }; + return path.startsWith("/writing/") || path.startsWith("/library/"); } diff --git a/package.json b/package.json index 543ce38..0f66528 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "www-aaronjy-me", - "version": "2.1.2", + "version": "2.2.0", "private": true, "type": "module", "lint-staged": { diff --git a/public/robots.txt b/public/robots.txt index 6a8d464..82dee3e 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -7,3 +7,4 @@ Host: https://www.aaronjy.me # Sitemaps Sitemap: https://www.aaronjy.me/sitemap.xml +Sitemap: https://www.aaronjy.me/server-sitemap-index.xml diff --git a/public/sitemap-0.xml b/public/sitemap-0.xml deleted file mode 100644 index 5ddf8e5..0000000 --- a/public/sitemap-0.xml +++ /dev/null @@ -1,14 +0,0 @@ - - -https://www.aaronjy.me/1 -https://www.aaronjy.me/about/0.8 -https://www.aaronjy.me/cv/0.8 -https://www.aaronjy.me/tags/0.8 -https://www.aaronjy.me/writing/0.8 -https://www.aaronjy.me/writing/attitudes-to-reading/0.6Tue, 18 Mar 2025 00:00:00 GMT -https://www.aaronjy.me/writing/moving-from-github-to-forgejo/0.6Sun, 16 Mar 2025 00:00:00 GMT -https://www.aaronjy.me/writing/performance-considerations-tcp-game-server/0.6Sun, 23 Feb 2025 21:12:37 GMT -https://www.aaronjy.me/writing/quick-reflection-katherine-may/0.6Sun, 09 Mar 2025 00:00:00 GMT -https://www.aaronjy.me/writing/static-site-on-google-cloud/0.6Wed, 01 May 2024 00:00:00 GMT -https://www.aaronjy.me/writing/support-content-filte-structure-changes-on-a-static-site/0.6Mon, 18 Mar 2024 16:47:32 GMT - \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml index e2b20c3..8b0679a 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -1,7 +1,45 @@ -https://www.aaronjy.me/cvweekly0.7 -https://www.aaronjy.me/libraryweekly0.7 -https://www.aaronjy.me/tagsweekly0.7 -https://www.aaronjy.me/writingweekly0.7 +https://www.aaronjy.me/cv0.8 +https://www.aaronjy.me/library0.8 +https://www.aaronjy.me/tags0.8 +https://www.aaronjy.me/writing0.8 +https://www.aaronjy.me/library/the-alchemist0.6 +https://www.aaronjy.me/library/the-invisible-man0.6 +https://www.aaronjy.me/library/wintering-the-power-of-rest-and-retreat-in-difficult-times0.6 +https://www.aaronjy.me/library/the-time-machine0.6 +https://www.aaronjy.me/library/when-the-moon-hits-your-eye0.6 +https://www.aaronjy.me/library/the-song-of-achilles0.6 +https://www.aaronjy.me/library/to-be-taught-if-fortunate0.6 +https://www.aaronjy.me/library/on-tyranny0.6 +https://www.aaronjy.me/library/the-dangers-of-smoking-in-bed0.6 +https://www.aaronjy.me/library/the-midnight-library0.6 +https://www.aaronjy.me/library/a-night-to-remember0.6 +https://www.aaronjy.me/library/sex-punishment0.6 +https://www.aaronjy.me/library/a-monster-calls0.6 +https://www.aaronjy.me/library/diary-of-an-oxygen-thief0.6 +https://www.aaronjy.me/library/19840.6 +https://www.aaronjy.me/library/alices-adventures-in-wonderland0.6 +https://www.aaronjy.me/library/the-nature-of-alexander0.6 +https://www.aaronjy.me/library/test0.6 +https://www.aaronjy.me/library/eleven-kinds-of-loneliness0.6 +https://www.aaronjy.me/library/star-maker0.6 +https://www.aaronjy.me/library/stray-reflections0.6 +https://www.aaronjy.me/library/stasiland-stories-from-behind-the-berlin-wall0.6 +https://www.aaronjy.me/library/cities-that-shaped-the-ancient-world0.6 +https://www.aaronjy.me/library/animal-farm0.6 +https://www.aaronjy.me/library/a-wizard-of-earthsea0.6 +https://www.aaronjy.me/library/one-thousand-and-one-nights-a-retelling0.6 +https://www.aaronjy.me/library/the-tombs-of-atuan0.6 +https://www.aaronjy.me/library/childhoods-end0.6 +https://www.aaronjy.me/library/the-farthest-shore0.6 +https://www.aaronjy.me/about0.8 +https://www.aaronjy.me1 +https://www.aaronjy.me/writing/migrating-from-github-to-forgejo0.6 +https://www.aaronjy.me/writing/performance-considerations-when-writing-a-tcp-game-server-in-dotnet0.6 +https://www.aaronjy.me/writing/deploying-aaronjy-me-on-a-google-storage-bucket0.6 +https://www.aaronjy.me/writing/supporting-content-file-structure-changes-on-a-static-site0.6 +https://www.aaronjy.me/writing/attitudes-to-reading-and-how-mine-have-changed0.6 +https://www.aaronjy.me/writing/a-reflection-on-wintering-by-katherine-may0.6 +https://www.aaronjy.me/writing/how-my-adhd-makes-handling-relationships-difficult0.6 \ No newline at end of file diff --git a/src/components/Loading/Loading.jsx b/src/components/Loading/Loading.jsx new file mode 100644 index 0000000..99672a0 --- /dev/null +++ b/src/components/Loading/Loading.jsx @@ -0,0 +1,3 @@ +export default function Loading() { + return

Loading...

; +} diff --git a/src/pages/[[...path]].jsx b/src/pages/[[...path]].jsx index a4e3b8e..3cc9c8c 100644 --- a/src/pages/[[...path]].jsx +++ b/src/pages/[[...path]].jsx @@ -1,16 +1,35 @@ -import { - FailedFetchBasicPageError, - FailedFetchBasicPagesError, -} from "@/errors"; +import Loading from "@/components/Loading/Loading"; +import { FailedFetchBasicPagesError } from "@/errors"; import DefaultLayout from "@/layouts/DefaultLayout/DefaultLayout"; import { mdxComponents } from "@/lib/mdx-components"; import { fetchBasicPages } from "@/services/content-service"; import { MDXClient } from "next-mdx-remote-client"; import { serialize } from "next-mdx-remote-client/serialize"; import { NextSeo } from "next-seo"; +import { useRouter } from "next/router"; -export async function getServerSideProps({ params }) { +export async function getStaticPaths() { + const res = await fetchBasicPages(["path"]); + + if (!res.ok) { + throw new FailedFetchBasicPagesError(await res.text()); + } + + const pages = (await res.json()).data; + + return { + paths: pages.map((page) => ({ + params: { + path: [page.path ?? ""], + }, + })), + fallback: true, + }; +} + +export async function getStaticProps({ params }) { const { path } = params; + const res = await fetchBasicPages([], { path: { _eq: path?.join("/") ?? null, @@ -26,6 +45,7 @@ export async function getServerSideProps({ params }) { if (!page) { return { notFound: true, + revalidate: 60, }; } @@ -37,10 +57,21 @@ export async function getServerSideProps({ params }) { title, mdxSource, }, + revalidate: 60, }; } export default function BasicPage({ title, mdxSource }) { + const { isFallback } = useRouter(); + + if (isFallback) { + return ( + + + + ); + } + if (!mdxSource || "error" in mdxSource) { return

Something went wrong: {mdxSource?.error ?? "???"}

; } diff --git a/src/pages/cv/index.js b/src/pages/cv/index.js index 585f75a..88e992d 100644 --- a/src/pages/cv/index.js +++ b/src/pages/cv/index.js @@ -7,7 +7,7 @@ import { FailedFetchCVError } from "@/errors"; export const Title = "CV"; -export async function getServerSideProps() { +export async function getStaticProps() { const res = await fetchCV([]); if (!res.ok) { @@ -18,6 +18,7 @@ export async function getServerSideProps() { if (!cv) { return { notFound: true, + revalidate: 60, }; } @@ -31,6 +32,7 @@ export async function getServerSideProps() { certifications, experience, }, + revalidate: 60, }; } diff --git a/src/pages/library/[slug].js b/src/pages/library/[slug].js index 03af892..35ae3aa 100644 --- a/src/pages/library/[slug].js +++ b/src/pages/library/[slug].js @@ -6,37 +6,33 @@ import { FailedFetchBookReviewError, FailedFetchBookReviewsError, } from "@/errors"; +import { useRouter } from "next/router"; +import Loading from "@/components/Loading/Loading"; -// export async function getStaticPaths () { -// const res = await fetchBookReviews(['slug'], { -// status: 'published' -// }) +export async function getStaticPaths() { + const res = await fetchBookReviews(["slug"], { + status: "published", + }); -// if (!res.ok) { -// throw new FailedFetchBookReviewsError(await res.text()) -// } - -// const reviews = (await res.json()).data - -// return { -// paths: reviews.map(post => ({ -// params: { -// slug: post.slug -// } -// })), -// fallback: false // false or "blocking" -// } -// } - -export const getServerSideProps = async ({ params }) => { - const { slug } = params; - - if (!slug) { - return { - notFound: true, - }; + if (!res.ok) { + throw new FailedFetchBookReviewsError(await res.text()); } + const reviews = (await res.json()).data; + + return { + paths: reviews.map((post) => ({ + params: { + slug: post.slug, + }, + })), + fallback: true, + }; +} + +export const getStaticProps = async ({ params }) => { + const { slug } = params; + const res = await fetchBookReviews([], { slug, status: "published", @@ -50,6 +46,7 @@ export const getServerSideProps = async ({ params }) => { if (!review) { return { notFound: true, + revalidate: 60, }; } @@ -61,13 +58,17 @@ export const getServerSideProps = async ({ params }) => { review, html, }, + revalidate: 60, }; }; export default function LibrarySingle({ review, html }) { + const { isFallback } = useRouter(); + return ( - + {!isFallback && } + {isFallback && } ); } diff --git a/src/pages/server-sitemap-index.xml/index.jsx b/src/pages/server-sitemap-index.xml/index.jsx new file mode 100644 index 0000000..a461c3f --- /dev/null +++ b/src/pages/server-sitemap-index.xml/index.jsx @@ -0,0 +1,29 @@ +import { + fetchBasicPages, + fetchBookReviews, + fetchPosts, +} from "@/services/content-service"; +import { getServerSideSitemapIndexLegacy } from "next-sitemap"; + +const siteUrl = process.env.SITE_URL || "https://www.aaronjy.me"; + +export const getServerSideProps = async (ctx) => { + const [basicPagesResp, bookReviewsResp, postsResp] = await Promise.all([ + fetchBasicPages().then((res) => res.json()), + fetchBookReviews().then((res) => res.json()), + fetchPosts().then((res) => res.json()), + ]); + + const urls = [ + ...basicPagesResp.data.map((entry) => `${siteUrl}/${entry.path ?? ""}`), + ...bookReviewsResp.data.map( + (entry) => `${siteUrl}/library/${entry.slug ?? ""}`, + ), + ...postsResp.data.map((entry) => `${siteUrl}/writing/${entry.slug ?? ""}`), + ]; + + return getServerSideSitemapIndexLegacy(ctx, [...urls]); +}; + +// Default export to prevent next.js errors +export default function SitemapIndex() {} diff --git a/src/pages/writing/[slug].js b/src/pages/writing/[slug].js index 1133fea..49a6ea0 100644 --- a/src/pages/writing/[slug].js +++ b/src/pages/writing/[slug].js @@ -3,8 +3,31 @@ import DefaultLayout from "@/layouts/DefaultLayout/DefaultLayout"; import Article from "@/components/Article/Article"; import { fetchPosts, markdownToHtml } from "@/services/content-service"; import { FailedFetchPostError, FailedFetchPostsError } from "@/errors"; +import { useRouter } from "next/router"; +import Loading from "@/components/Loading/Loading"; -export const getServerSideProps = async ({ params }) => { +export async function getStaticPaths() { + const res = await fetchPosts(["slug"], { + status: "published", + }); + + if (!res.ok) { + throw new FailedFetchPostsError(await res.text()); + } + + const posts = (await res.json()).data; + + return { + paths: posts.map((post) => ({ + params: { + slug: post.slug, + }, + })), + fallback: true, + }; +} + +export const getStaticProps = async ({ params }) => { const { slug } = params; const res = await fetchPosts([], { slug, @@ -19,6 +42,7 @@ export const getServerSideProps = async ({ params }) => { if (!post) { return { notFound: true, + revalidate: 60, }; } @@ -30,13 +54,17 @@ export const getServerSideProps = async ({ params }) => { post, html, }, + revalidate: 60, }; }; export default function WritingSingle({ post, html }) { + const { isFallback } = useRouter(); + return ( -
+ {!isFallback &&
} + {isFallback && } ); }