Routing
Routing is delegated to each respective framework using helpers from the createSource
utilitiy. This gives you full control for how to render content and documentation. The following demonstrates how to set up routing using the paths
helper from createSource
in Next.js.
Naming Conventions
Source files named <Component>.tsx
can have an accompanying <Component>.mdx
. This is the same for other files like hooks or utilities. For example, useHook.ts
and useHook.mdx
.
For index.ts
or index.tsx
, the accompanying file can be index.md
, index.mdx
, README.md
, or README.mdx
.
Rendering Content
MDX content can be rendered using the Content
component exported from a source item in an App Router page:
import { createSource } from 'mdxts'
const allDocs = createSource('docs/**/*.mdx')
export default async function Page({ params }: { params: { slug: string[] } }) {
const { Content } = await allDocs.get(params.slug)
return <Content />
}
Configuring Base Directories
Depending on how you want paths
structured in your project, you can set a base directory when defining sources with createSource
:
import { createSource } from 'mdxts'
export const allPosts = createSource('src/posts/*.mdx', {
baseDirectory: 'posts',
})
This will affect the paths
method and how the get
method is used to retrieve content:
import { notFound } from 'next/navigation'
import { allPosts } from '../../posts'
export default async function Page({ params }: { params: { slug: string } }) {
// now you don't need to prefix the "/src/posts" path
const post = await allPosts.get(params.slug)
if (!post) {
return notFound()
}
const { Content } = post
return <Content />
}
Visit the createSource
API documentation for more information on how to configure sources.
Rendering Type Documentation
Type documentation can be rendered using the exportedTypes
metadata from a source item. Any associated MDX content can be rendered using the Content
component if present:
import { createSource } from 'mdxts'
const allComponents = createSource('components/**/*.tsx')
export default async function Page({ params }: { params: { slug: string[] } }) {
const { Content, exportedTypes } = await allComponents.get(params.slug)
return (
<>
{Content ? <Content /> : null}
<ul>
{exportedTypes.map((type) => (
<li key={type.name}>
<h4>{type.name}</h4>
<p>{type.description}</p>
{type.types.map((type) =>
type.properties ? (
<ul>
{type.properties.map((property) => (
<li key={property.name}>
<h5>{property.name}</h5>
<p>{property.description}</p>
</li>
))}
</ul>
) : (
type.text
)
)}
</li>
))}
</ul>
</>
)
}
When targeting JavaScript or TypeScript files, a few heuristics are used to infer public metadata:
- First, package exports will be used if present.
-
Otherwise, the presence of an
index
file will be used to infer public exports. - Finally, if both fail to find public entry source files, the entire directory will be analyzed.
Generating Static Routes
Use the paths
method for a source to generate static routes:
import { createSource } from 'mdxts'
const allDocs = createSource('docs/**/*.mdx')
export function generateStaticParams() {
return allDocs.paths().map((pathname) => ({ slug: pathname }))
}
export default async function Page({ params }: { params: { slug: string[] } }) {
const { Content } = await allDocs.get(params.slug)
return Content ? <Content /> : null
}
Rendering Examples
Examples collected from .examples.tsx
files and examples
directories are available on a source item through examplePaths
and getExample
helpers. The exported example can be rendered using moduleExport
:
import { createSource } from 'mdxts'
const allComponents = createSource('components/**/*.tsx')
export async function generateStaticParams() {
return (await allComponents.examplePaths()).map((pathname) => ({
example: pathname,
}))
}
export default async function Page({
params,
}: {
params: { example: string[] }
}) {
const example = await allComponents.getExample(params.example)
return <example.moduleExport />
}