From e2bf337bb2e795c3ea83ec552536d623d450c2bd Mon Sep 17 00:00:00 2001 From: joostdecock Date: Sat, 20 May 2023 14:06:39 +0200 Subject: [PATCH] fix(org): Load MDX dynamically to reduce the number of routes Prior to this commit we'd generate a page for each MDX document as that avoids having to load MDX dynamically (which can be tricky) or through static props (which causes issues with serialization). However, Vercel (which hosts for us) has an upper limit on the number of routes, and because of this extensive documentation, we blew passed it with this approach. This changes to a dynamic resolution of MDX content with an async import in the useEffect hook. This should drastically reduce the number of routes and make Vercel happy. I didn't do much digging into the effects of this on SSR. If it turns out it's causes issues, we'll deal with it at that time. --- .gitignore | 1 - markdown/org/docs/en.md | 7 - sites/org/pages/docs/[...slug].mjs | 232 +++++++++++++++++++++++++++++ sites/org/pages/docs/index.mjs | 50 +++++++ 4 files changed, 282 insertions(+), 8 deletions(-) create mode 100644 sites/org/pages/docs/[...slug].mjs create mode 100644 sites/org/pages/docs/index.mjs diff --git a/.gitignore b/.gitignore index ff730ab991a..67f7e0f8fbb 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,6 @@ sites/lab/pages !sites/lab/pages/*/index.js # org auto-generated pages -sites/org/pages/docs/* sites/org/pages/new/pattern/* # Node dependencies diff --git a/markdown/org/docs/en.md b/markdown/org/docs/en.md index 0bcc7a474fd..c3626ddc79f 100644 --- a/markdown/org/docs/en.md +++ b/markdown/org/docs/en.md @@ -17,10 +17,3 @@ developer/contributor docs, please refer to - - -We should diataxis our docs - - - - diff --git a/sites/org/pages/docs/[...slug].mjs b/sites/org/pages/docs/[...slug].mjs new file mode 100644 index 00000000000..3da341e7833 --- /dev/null +++ b/sites/org/pages/docs/[...slug].mjs @@ -0,0 +1,232 @@ +// Used in static paths +import mdxPaths from 'site/prebuild/mdx.paths.js' +// Dependencies +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' +// Hooks +import { useState, useEffect } from 'react' +// Components +import Head from 'next/head' +import { PageWrapper, ns } from 'shared/components/wrappers/page.mjs' +import { Spinner } from 'shared/components/spinner.mjs' +import { components } from 'shared/components/mdx/index.mjs' +import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs' +//import { TocWrapper } from 'shared/components/wrappers/toc.mjs' + +/* + * PLEASE READ THIS BEFORE YOU TRY TO REFACTOR THIS PAGE + * + * You will notice that this page has a page component for each language + * and that those components are 95% identical. So you may be thinking: + * + * This is not DRY, let me refactor this real quick + * + * Before you do so, please reflect on these topics: + * + * - Do you know the pitfalls of dynamic imports in Webpack? + * - Do you know how much documentation we have? + * - Do you know we support 5 languages? + * + * If you do know all of these thigns, and you think you can improve this page. Go ahead. + * + * If you are not sure, then I would recommend you find something else to work on, unless + * you consider this a learning opportunity. + * + * joost + * + */ + +export const Loading = () => ( + +) + +export const HeadInfo = ({ frontmatter, locale, slug }) => ( + + + + + + + + + + + + + {frontmatter.title} - FreeSewing.org + +) + +export const Page = ({ page, frontmatter, slug, locale, MDX }) => ( + + +
+ {false && frontmatter.toc && ( +
+ {/* FIXME: Implement toc plugin to add it to the frontmatter */} + {/* */} +
+ )} + {MDX} +
+
+) + +const EnDocsPage = ({ page, slug }) => { + // State + const [frontmatter, setFrontmatter] = useState({ title: 'FreeSewing.org' }) + const [MDX, setMDX] = useState() + + /* Load MDX dynamically */ + useEffect(() => { + const loadMDX = async () => { + import(`../../../../markdown/org/${slug}/en.md`).then((mod) => { + setFrontmatter(mod.frontmatter) + const Component = mod.default + setMDX() + }) + } + loadMDX() + }, [slug]) + + return +} + +const FrDocsPage = ({ page, slug }) => { + // State + const [frontmatter, setFrontmatter] = useState({ title: 'FreeSewing.org' }) + const [MDX, setMDX] = useState() + + /* Load MDX dynamically */ + useEffect(() => { + const loadMDX = async () => { + import(`../../../../markdown/org/${slug}/fr.md`).then((mod) => { + setFrontmatter(mod.frontmatter) + const Component = mod.default + setMDX() + }) + } + loadMDX() + }, [slug]) + + return +} + +const EsDocsPage = ({ page, slug }) => { + // State + const [frontmatter, setFrontmatter] = useState({ title: 'FreeSewing.org' }) + const [MDX, setMDX] = useState() + + /* Load MDX dynamically */ + useEffect(() => { + const loadMDX = async () => { + import(`../../../../markdown/org/${slug}/es.md`).then((mod) => { + setFrontmatter(mod.frontmatter) + const Component = mod.default + setMDX() + }) + } + loadMDX() + }, [slug]) + + return +} + +const DeDocsPage = ({ page, slug }) => { + // State + const [frontmatter, setFrontmatter] = useState({ title: 'FreeSewing.org' }) + const [MDX, setMDX] = useState() + + /* Load MDX dynamically */ + useEffect(() => { + const loadMDX = async () => { + import(`../../../../markdown/org/${slug}/de.md`).then((mod) => { + setFrontmatter(mod.frontmatter) + const Component = mod.default + setMDX() + }) + } + loadMDX() + }, [slug]) + + return +} + +const NlDocsPage = ({ page, slug }) => { + // State + const [frontmatter, setFrontmatter] = useState({ title: 'FreeSewing.org' }) + const [MDX, setMDX] = useState() + + /* Load MDX dynamically */ + useEffect(() => { + const loadMDX = async () => { + import(`../../../../markdown/org/${slug}/nl.md`).then((mod) => { + setFrontmatter(mod.frontmatter) + const Component = mod.default + setMDX() + }) + } + loadMDX() + }, [slug]) + + return +} + +const DocsPage = (props) => { + if (props.locale === 'en') return + if (props.locale === 'fr') return + if (props.locale === 'es') return + if (props.locale === 'de') return + if (props.locale === 'nl') return +} + +export default DocsPage + +/* + * getStaticProps() is used to fetch data at build-time. + * To learn more, see: https://nextjs.org/docs/basic-features/data-fetching + */ +export async function getStaticProps({ locale, params }) { + return { + props: { + ...(await serverSideTranslations('en', ['docs', ...ns])), + slug: 'docs/' + params.slug.join('/'), + locale, + page: { + locale, + path: ['docs', ...params.slug], + }, + }, + } +} + +/* + * getStaticPaths() is used to specify for which routes (think URLs) + * this page should be used to generate the result. + * + * On this page, it is returning a list of routes (think URLs) for all + * the mdx (markdown) content. + * That list comes from mdxMeta, which is build in the prebuild step + * and contains paths, titles, and intro for all markdown. + * + * To learn more, see: https://nextjs.org/docs/basic-features/data-fetching + */ +export async function getStaticPaths() { + const somePaths = mdxPaths + .filter((path) => path.split('/').length < 5) + .filter((path) => path !== 'docs') + + return { + paths: [ + ...somePaths.map((key) => `/${key}`), + ...somePaths.map((key) => `/es/${key}`), + ...somePaths.map((key) => `/de/${key}`), + ...somePaths.map((key) => `/fr/${key}`), + ...somePaths.map((key) => `/nl/${key}`), + ], + fallback: 'blocking', + } +} diff --git a/sites/org/pages/docs/index.mjs b/sites/org/pages/docs/index.mjs new file mode 100644 index 00000000000..dbd8b1a6ced --- /dev/null +++ b/sites/org/pages/docs/index.mjs @@ -0,0 +1,50 @@ +// Dependencies +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' +// Hooks +import { useState, useEffect } from 'react' +// Components +import { ns } from 'shared/components/wrappers/page.mjs' +import { components } from 'shared/components/mdx/index.mjs' +import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs' +//import { TocWrapper } from 'shared/components/wrappers/toc.mjs' +import { Loading, HeadInfo, Page } from './[...slug].mjs' + +const DocsHomePage = ({ page, slug, locale }) => { + // State + const [frontmatter, setFrontmatter] = useState({ title: 'FreeSewing.org' }) + const [MDX, setMDX] = useState() + + /* Load MDX dynamically */ + useEffect(() => { + const loadMDX = async () => { + import(`../../../../markdown/org/docs/${locale}.md`).then((mod) => { + setFrontmatter(mod.frontmatter) + const Component = mod.default + setMDX() + }) + } + loadMDX() + }, [slug]) + + return +} + +export default DocsHomePage + +/* + * getStaticProps() is used to fetch data at build-time. + * To learn more, see: https://nextjs.org/docs/basic-features/data-fetching + */ +export async function getStaticProps({ locale }) { + return { + props: { + ...(await serverSideTranslations('en', ['docs', ...ns])), + slug: 'docs', + locale, + page: { + locale, + path: ['docs'], + }, + }, + } +}