• This repository has been archived on 27/Feb/2022
  • Stars
    star
    190
  • Rank 203,739 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created almost 4 years ago
  • Updated almost 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

next-mdx provides a set of helper functions for fetching and rendering local MDX files. It handles relational data, supports custom components, is TypeScript ready and really fast.

⚠️ This project has been retired. Consider using next-mdx-remote or mdx-bundler or nextra.

next-mdx

Test License PRs welcome! Follow @shadcn

next-mdx provides a set of helper functions for fetching and rendering local MDX files. It handles relational data, supports custom components, TypeScript ready and is really fast.

next-mdx is great for building mdx-powered pages, multi-user blogs, category pages..etc.

next-mdx-relational-data

Table of Contents

Demo

https://next-mdx-example.vercel.app

Quick Start

Learn how next-mdx works by looking at examples.

  1. Go to example-page
  2. Open next-mdx.json to see the sample configuration.
  3. Open pages/[[...slug]].tsx to see how MDX files are fetched and rendered.
  4. See types/index.d.ts for TypeScript.

Examples

Click to expand examples.

next-mdx.json
{
  "post": {
    "contentPath": "content/posts",
    "basePath": "/blog",
    "sortBy": "date",
    "sortOrder": "desc"
  },
}
pages/posts/[...slug].jsx
import { useHydrate } from "next-mdx/client"
import { getMdxNode, getMdxPaths } from "next-mdx/server"

export default function PostPage({ post }) {
const content = useHydrate(post)

  return (
    <article>
      <h1 variant="heading.title">{post.frontMatter.title}</h1>
      {post.frontMatter.excerpt ? (
        <p variant="text.lead" mt="4">
          {post.frontMatter.excerpt}
        </p>
      ) : null}
      <hr />
      {content}
    </article>
  )

}

export async function getStaticPaths() {
return {
paths: await getMdxPaths("post"),
fallback: false,
}
}

export async function getStaticProps(context) {
const post = await getMdxNode("post", context)

  if (!post) {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      post,
    },
  }

}

Installation


npm i --save next-mdx

Configuration

Create a next-mdx.json file at the root of your project with the following:

{
  "post": {
    "contentPath": "content/posts",
    "basePath": "/blog",
    "sortBy": "date",
    "sortOrder": "desc"
  },
  "category": {
    "contentPath": "content/categories"
  }
}
  1. post, category and author keys are unique IDs used as references for your MDX types.
  2. contentPath (required) is where your MDX files are located.
  3. basePath (optional) is the path used for generating URLs.
  4. sortBy (optional, defaults to title) is the name of the frontMatter field used for sorting.
  5. sortOrder (optional, defaults to asc) is the sorting order.

Reference

next-mdx exposes 6 main helper functions:

  • getMdxPaths(sourceName: string)
  • getNode(sourceName, context)
  • getAllNodes(sourceName)
  • getMdxNode(sourceName, context, params)
  • getAllMdxNodes(sourceName, params)
  • useHydrate(node, params)

getMdxPaths

getMdxPaths(sourceName: string) returns an array of path params which can be passed directly to paths in getStaticPaths`.

  • sourceName is the unique ID defined in next-mdx.json

Example

// pages/blog/[...slug].js
import { getMdxPaths } from "next-mdx/server"

export async function getStaticPaths() {
  return {
    paths: await getMdxPaths("post"),
    fallback: false,
  }
}

getNode

getNode(sourceName, context) returns an MDXNode with frontMatter and relational data but without MDX data. This is really fast and cached.

Use this instead of getMdxNode if you are not rendering MDX content on a page.

  • sourceName is the unique ID defined in next-mdx.json
  • context is the context passed to getStaticProps or the slug as a string.

Example

// pages/blog/[...slug].js
import { getNode } from "next-mdx/server"

export async function getStaticProps(context) {
  const post = await getNode("post", context)

  if (!post) {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      post,
    },
  }
}

getAllNodes

getAllNodes(sourceName) returns all MdxNode of the given type/source with frontMatter and relational data but without MDX data. This is also really fast and cached.

  • sourceName is the unique ID defined in next-mdx.json

Example

import { getAllNodes } from "next-mdx/server"

export async function getStaticProps() {
  return {
    props: {
      posts: await getAllNodes("post"),
    },
  }
}

getMdxNode

getMdxNode(sourceName, context, params) returns an MDXNode.

  • sourceName is the unique ID defined in next-mdx.json
  • context is the context passed to getStaticProps or the slug as a string.
  • params:
{
  components?: MdxRemote.Components
  scope?: Record<string, unknown>
  provider?: MdxRemote.Provider
  mdxOptions?: {
    remarkPlugins?: Pluggable[]
    rehypePlugins?: Pluggable[]
    hastPlugins?: Pluggable[]
    compilers?: Compiler[]
    filepath?: string
  }
}

Example

// pages/blog/[...slug].js
import { getMdxNode } from "next-mdx/server"

export async function getStaticProps(context) {
  const post = await getMdxNode("post", context)

  if (!post) {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      post,
    },
  }
}

getAllMdxNodes

getAllMdxNodes(sourceName, params) returns all MdxNode of the given type/source.

  • sourceName is the unique ID defined in next-mdx.json
  • params:
{
  components?: { name: React.Component },
  scope?: {},
  provider?: { component: React.Component, props: Record<string, unknown> },
  mdxOptions: {
    remarkPlugins: [],
    rehypePlugins: [],
    hastPlugins: [],
    compilers: [],
  }
}

Example

import { getAllMdxNodes } from "next-mdx/server"

export async function getStaticProps() {
  const posts = await getAllMdxNodes("post")

  return {
    props: {
      posts: posts.filter((post) => post.frontMatter.featured),
    },
  }
}

useHydrate

useHydrate(node, params) is used on the client side for hydrating static content.

  • node is the MdxNode object
  • params:
{
  components?: { name: React.Component },
  provider?: { component: React.Component, props: Record<string, unknown> }
}

Example

import { useHydrate } from "next-mdx/client"

export default function PostPage({ post }) {
  const content = useHydrate(post)

  return (
    <div>
      <h1>{post.frontMatter.title}</h1>

      {content}
    </div>
  )
}

getAllNodes vs getAllMdxNodes

Use getAllNodes when you need nodes without the MDX content. It is backed by a cache and is really fast. This is handy when you need a list of nodes (example post teasers) and you're not using the MDX content.

MDX Components

To use components inside MDX files, you need to pass the components to both getMdxNode/getAllMdxNodes and useHydrate.

Example

import { getMdxNode } from "next-mdx/server"
import { useHydrate } from "next-mdx/client"

export function Alert({ text }) {
  return <p>{text}</p>
}

export default function PostPage({ post }) {
  const content = useHydrate(post, {
    components: {
      Alert,
    },
  })

  return (
    <div>
      <h1>{post.frontMatter.title}</h1>

      {content}
    </div>
  )
}

export async function getStaticProps(context) {
  const post = await getMdxNode("post", context, {
    components: {
      Alert,
    },
  })

  return {
    props: {
      post,
    },
  }
}

MDX Options

MDX options can be passed as params to both getMdxNode(sourceName, context, params) and getAllMdxNodes(sourceName, params) where params takes the shape of:

export interface MdxParams {
  components?: MdxRemote.Components
  scope?: Record<string, unknown>
  provider?: MdxRemote.Provider
  mdxOptions?: {
    remarkPlugins?: Pluggable[]
    rehypePlugins?: Pluggable[]
    hastPlugins?: Pluggable[]
    compilers?: Compiler[]
    filepath?: string
  }
}

Relational Data

When retrieving nodes with getMdxNode or getAllMdxNodes, next-mdx will automatically infer relational data from frontMatter keys.

Convention

  1. The frontMatter field name must be the same as the key defined in next-mdx.json
  2. The frontMatter field must be an array of values.

Example

Given the following MDX files.

.
└── content
    β”œβ”€β”€ categories
    β”‚   └── category-a.mdx
    β”‚   └── category-b.mdx
    └── posts:
        └── example-post.mdx

In example-post you can reference related categories using the following:

---
title: Example Post
category:
  - category-a
---

You can then access the categories as follows:

const post = getMdxNode("post", context)

// post.relationships.category

Plugins

TypeScript

Define your node types as follows:

interface Post extends MdxNode<FrontMatterFields> {}

Example

import { MdxNode } from "next-mdx/server"

interface Category
  extends MdxNode<{
    name: string
  }> {}

interface Post
  extends MdxNode<{
    title: string
    excerpt?: string
    category?: string[]
  }> {
  relationships?: {
    category: Category[]
  }
}

You can then use Post as the return type for getNode, getAllNodes, getMdxNode and getAllMdxNode:

const post = await getMdxNode<Post>("post", context)

const posts = await getAllNodes<Post>("post")

License

Licensed under the MIT license.

More Repositories

1

taxonomy

An open source application built using the new router, server components and everything new in Next.js 13.
TypeScript
13,813
star
2

next-contentlayer

A template with Next.js 13 app dir, Contentlayer, Tailwind CSS and dark mode.
TypeScript
674
star
3

next-template

A Next.js 13 template for building apps with Radix UI and Tailwind CSS.
TypeScript
277
star
4

crepido

Create (kanban) boards to track users and projects from flat markdown files. Supports multiple projects, timers, progress bars, collapsible sections and custom colors.
CSS
178
star
5

Sketch-Navigator

"Sketch Navigator lets you quickly jump to any specific artboard without having to scan the all too easily cluttered Layers List in the app’s left-hand pane." - Khoi Vinh
JavaScript
160
star
6

drupal-template-helper

Debug Drupal 8 templates in Chrome Devtools. drupal-template-helper is a chrome extension for Drupal that lists all available templates and the preprocess hooks to use to customize your templates.
JavaScript
117
star
7

license-generator

Generates a license for your open source project.
JavaScript
110
star
8

example-ui-themes

TypeScript
78
star
9

Sketch-Sass-Colors

Displays colors as Sass variables for Sketch
70
star
10

next-template-jsx

A Next.js 13 template for building apps with Radix UI and Tailiwnd CSS.
JavaScript
61
star
11

kaizoku

A CLI for the Pirate Bay that can search for torrent and automatically add it to your torrent client or stream it using VLC.
JavaScript
60
star
12

tree-to-image

A tree to image generator using @vercel/og
TypeScript
53
star
13

subdb-cli

Download subtitles from the command line
JavaScript
44
star
14

next-cms-wordpress

An example Next.js 13 app built from WordPress data.
TypeScript
36
star
15

vite-template

Created with CodeSandbox
TypeScript
29
star
16

Google-Form-Octopress

A Liquid tag to embed Google Forms in Octopress
Ruby
24
star
17

gatsby-theme-twentytwentyone

This is the WordPress Twenty Twenty-One theme built for Gatsby.
CSS
23
star
18

example-battlefield-chart

example chart
TypeScript
17
star
19

next-template-debug

next-template-debug
TypeScript
12
star
20

CrossBrowse

Simple proof of concept for tracking element position across clients.
JavaScript
12
star
21

status.arshad.io

CSS
10
star
22

next-app-tailwind-template

A (personal) starter template with app dir and Tailwind CSS.
TypeScript
8
star
23

next-prisma-app

next-prisma-app
TypeScript
8
star
24

next-drupal-examples

Examples for Next.js for Drupal
TypeScript
7
star
25

next-ghost

TypeScript
6
star
26

radix-bootswatch

Bootswatch for Radix
CSS
6
star
27

compass_radix

A Compass extension for Drupal's Radix theme.
CSS
6
star
28

datamaps-custom-marker

A datamaps plugin for custom map markers
JavaScript
6
star
29

gatsby-plugin-theme-helpers

An experimental plugin to help with component shadowing discovery.
JavaScript
6
star
30

gatsby-starter-flex

A Gatsby starter for the Flex theme.
JavaScript
5
star
31

value

Simplified Twig template variables for Drupal
PHP
5
star
32

nextjs-gatsby

This is nextjs.org home page built with Gatsby and Reflex.
JavaScript
4
star
33

reflexjs-example

https://reflexjs-example.vercel.app
TypeScript
3
star
34

airtv

A CLI for TV shows air dates
JavaScript
3
star
35

gatsby-starter-phoenix

A Gatsby starter for Phoenix
JavaScript
3
star
36

create-shadcn

Template
3
star
37

next-debug-head

Debugging Head.tsx in Next.js 13
TypeScript
3
star
38

react_module_boilerplate

Boilerplate for Drupal 8 module with React, ES6, Babel and Webpack.
JavaScript
2
star
39

next-mdx-simple-blog

A simple blog with categories built using next-mdx.
TypeScript
2
star
40

reflex-redwood

JavaScript
2
star
41

simplytest-chrome

A Google Chrome extension for simplytest.me
JavaScript
2
star
42

mdx-toc

JavaScript
2
star
43

gatsby-example-flex

Demo site for the Gatsby Flex theme.
JavaScript
2
star
44

expressjs_starter

Template for Express app with Requirejs, Backbone, and Jade templating.
JavaScript
2
star
45

next-drupal-debug

JavaScript
2
star
46

scrapdo

Scrapdo is a scrapper for Drupal.org built with node.
JavaScript
2
star
47

slick

Slick carousel for Drupal
PHP
2
star
48

radix_stanley

Radix Stanley is a theme coded by BlackTie and ported to Drupal. It is based on Radix.
CSS
2
star
49

do-api

An API for drupal.org built with scrapdo and Express.
JavaScript
1
star
50

mdnext-reflexjs-demo

Demo for Nextjs, MDX and Reflexjs.
TypeScript
1
star
51

reflexjs-product-docs

Demo for gatsby-theme-doc
JavaScript
1
star
52

nextjs-middleware-validation

Validation middlewares for Next.js API routes with Yup.
TypeScript
1
star
53

h5bpbu

HTML 5 Boilerplate with Backbone.js and Underscore.js
JavaScript
1
star
54

jsonapi_config

Configuration for the JSON API module.
PHP
1
star
55

block_subtitle

This module allows subtitle to be added to blocks.
1
star
56

radix_bootswatch_themes

A collection of Radix Bootswatch themes.
CSS
1
star
57

vagrant-drupal

Vagrant for Drupal development
Ruby
1
star
58

drupal_tests

Skeleton Drupal feature for Acceptance testing with Behat
PHP
1
star
59

lerna-test

Shell
1
star
60

next-drupal-basic-starter

A simple starter for building your site with Next.js and Drupal.
TypeScript
1
star
61

teamworkpm

A node wrapper for the TeamworkPM API
JavaScript
1
star
62

twig_not_empty

Adds a Twig notEmpty test for Drupal 8
PHP
1
star
63

imgs

www.imgs.io
1
star
64

reflex-mdx-js

Example Reflex site using MDX and JSX components. See https://github.com/reflexjs/reflex to build your Reflex site.
JavaScript
1
star
65

next-debug-edge-runtime

next-debug-edge-runtime
TypeScript
1
star
66

wp-gatsby-extended

Extends the WPGatsby WordPress plugin with custom GraphQL Types.
PHP
1
star
67

adminify

Simplify the Drupal admin
1
star
68

gatsby-theme-phoenix-disqus

Gatsby theme with Disqus
JavaScript
1
star
69

radix_layouts

Responsive Panels layouts for Radix.
PHP
1
star
70

Tray

This module provides a tray to your Drupal site. This tray can be used as an application bar.
PHP
1
star
71

next-drupal-auth

TypeScript
1
star
72

cms-drupal

A statically generated blog example using Next.js and Drupal
JavaScript
1
star
73

next-mdx-post-snippet

TypeScript
1
star