Next.js Guide
The renoun toolkit enhances the Next.js framework with powerful content and documentation features.
The renoun toolkit provides file system querying, syntax highlighting, and api references, making it easier to create accurate and engaging content for blogs, documentation, and design systems powered by Next.js.
Install
To use renoun with Next.js, start with an existing or new Next.js project. If you don’t have a project yet, you can create one using the Next.js create command:
npx create-next-app@latest
Next, we need to install the renoun package dependencies:
npm install renoun ts-morphpnpm add renoun ts-morphyarn add renoun ts-morphbun add renoun ts-morphSetup
Modify the next scripts located in the project’s package.json file to use the renoun CLI. This will ensure that the renoun process starts before your Next.js server:
{
"scripts": {
"dev": "renoun next dev",
"build": "renoun next build"
}
}
Custom Server
Alternatively, if you don’t want to use the CLI, the renoun WebSocket server can be started manually using the createServer function:
import { createServer } from 'renoun/server'
const server = await createServer()Webpack Configuration
If you are using Webpack to bundle your Next.js project, you will need to configure the resolve.alias option to support ESM files. This will allow you to import renoun components and utilities without errors:
export default {
webpack(config) {
config.resolve.extensionAlias = {
'.js': ['.ts', '.tsx', '.js'],
}
return config
},
}MDX (Optional)
To enable writing MDX content in your Next.js application, we will use the @next/mdx package. This package allows you to author MDX content in your Next.js project. Additionally, you can use the pre-configured remarkPlugins and rehypePlugins from renoun.
First, install the Next.js MDX plugin:
npm install @next/mdxpnpm add @next/mdxyarn add @next/mdxbun add @next/mdxNow, add the plugin to your next.config file while optionally including the pre-configured remarkPlugins and rehypePlugins from the renoun package:
import createMDXPlugin from '@next/mdx'
import { remarkPlugins, rehypePlugins } from 'renoun'
const withMDX = createMDXPlugin({
extension: /\.mdx?$/,
options: {
remarkPlugins,
rehypePlugins,
},
})
export default withMDX({
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
})MDX Code Blocks
Use the CodeBlock component to override the code fences in your project’s mdx-components.tsx file:
import { CodeBlock } from 'renoun'
export function useMDXComponents() {
return { CodeBlock }
}The addCodeBlock rehype plugin from @renoun/mdx replaces the code fence pre element with a CodeBlock component that will receive the code fence meta as props.
For example, the following code fence with meta props defined:
```tsx allowErrors shouldFormat={false}
const a = 1
const b = a + '2'
```
Roughly yields the following:
<CodeBlock allowErrors shouldFormat={false}>
{`const a = 1\nconst b = a + '2'`}
</CodeBlock>
Querying the File System
The Directory utility in renoun lets you query and load files from your project’s file system. For example, to create a list of blog posts or documentation pages we can query all MDX files in a directory:
import { Directory } from 'renoun'
const posts = new Directory({
path: 'posts',
filter: '*.mdx',
loader: {
mdx: (path) => import(`@/posts/${path}.mdx`),
},
})
Next, we can use the Directory instance to render the contents of our MDX files:
import { Directory } from 'renoun'
const posts = new Directory({
path: 'posts',
filter: '*.mdx',
loader: {
mdx: (path) => import(`@/posts/${path}.mdx`),
},
})
export default async function Page(props: PageProps<'/posts/[slug]'>) {
const { slug } = await props.params
Property 'slug' does not exist on type 'unknown'. (2339) const post = await posts.getFile(slug, 'mdx')
const Content = await post.getExportValue('default')
return <Content />
}
This will create a collection of all MDX files in the posts directory and render them based on the provided slug.
Generating Links
A directory entry’s getPath method can generate a route path for each entry. For example, to generate a link to each post, you can iterate over the entries and use the entry’s getPath method:
import { Directory } from 'renoun'
import Link from 'next/link'
const posts = new Directory({
path: 'posts',
filter: '*.mdx',
loader: {
mdx: (path) => import(`@/posts/${path}.mdx`),
},
})
export default async function Page() {
const allPosts = await posts.getEntries()
return (
<>
<h1>Blog</h1>
<ul>
{allPosts.map(async (post) => {
const pathname = post.getPathname()
return (
<li key={pathname}>
<Link href={pathname}>{post.getTitle()}</Link>
</li>
)
})}
</ul>
</>
)
}
Directories are not limited to MDX files and can be used with any file type.
Ignoring files in dynamic imports
When using dynamic imports inside a Directory loader, you can tell Webpack to exclude certain files (e.g. tests or node modules) so they are not included in the bundle. To configure this, add a magic comment to the import call:
import { Directory } from 'renoun'
const posts = new Directory({
path: 'posts',
filter: '*.mdx',
loader: {
mdx: (path) => {
return import(
/* webpackExclude: /node_modules/ */
`@/posts/${path}.mdx`
)
},
},
})
Start
Now you can start your Next.js server with renoun enabled:
npm run devpnpm devyarn devbun run devCongratulations, you’ve successfully set up renoun with Next.js! You can now query other file system entries or use one of the many components available to enhance your content and documentation.