• This repository has been archived on 27/Feb/2022
  • Stars
    star
    188
  • Rank 198,801 (Top 5 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 3 years ago
  • Updated about 2 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

ui

Beautifully designed components built with Radix UI and Tailwind CSS.
TypeScript
11,065
star
3

next-contentlayer

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

gatsby-themes

A collection of open source, well designed, highly customizable and 100% free Gatsby themes for blazing fast sites. We are working on the next version of the Flex theme. See https://github.com/reflexjs/reflexjs
JavaScript
320
star
5

next-template

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

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
7

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
8

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
116
star
9

license-generator

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

Sketch-Sass-Colors

Displays colors as Sass variables for Sketch
70
star
11

next-template-jsx

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

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
13

tree-to-image

A tree to image generator using @vercel/og
TypeScript
50
star
14

subdb-cli

Download subtitles from the command line
JavaScript
44
star
15

next-cms-wordpress

An example Next.js 13 app built from WordPress data.
TypeScript
33
star
16

vite-template

Created with CodeSandbox
TypeScript
27
star
17

Google-Form-Octopress

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

gatsby-theme-twentytwentyone

This is the WordPress Twenty Twenty-One theme built for Gatsby.
CSS
21
star
19

CrossBrowse

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

next-template-debug

next-template-debug
TypeScript
11
star
21

next-prisma-app

next-prisma-app
TypeScript
8
star
22

next-app-tailwind-template

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

next-ghost

TypeScript
6
star
24

radix-bootswatch

Bootswatch for Radix
CSS
6
star
25

compass_radix

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

datamaps-custom-marker

A datamaps plugin for custom map markers
JavaScript
6
star
27

gatsby-plugin-theme-helpers

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

gatsby-starter-flex

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

value

Simplified Twig template variables for Drupal
PHP
5
star
30

next-drupal-examples

Examples for Next.js for Drupal
TypeScript
5
star
31

nextjs-gatsby

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

reflexjs-example

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

gatsby-starter-phoenix

A Gatsby starter for Phoenix
JavaScript
3
star
34

next-debug-head

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

react_module_boilerplate

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

next-mdx-simple-blog

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

reflex-redwood

JavaScript
2
star
38

mdx-toc

JavaScript
2
star
39

simplytest-chrome

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

expressjs_starter

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

gatsby-example-flex

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

scrapdo

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

slick

Slick carousel for Drupal
PHP
2
star
44

radix_stanley

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

do-api

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

mdnext-reflexjs-demo

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

reflexjs-product-docs

Demo for gatsby-theme-doc
JavaScript
1
star
48

nextjs-middleware-validation

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

h5bpbu

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

block_subtitle

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

jsonapi_config

Configuration for the JSON API module.
PHP
1
star
52

radix_bootswatch_themes

A collection of Radix Bootswatch themes.
CSS
1
star
53

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
54

vagrant-drupal

Vagrant for Drupal development
Ruby
1
star
55

drupal_tests

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

next-debug-edge-runtime

next-debug-edge-runtime
TypeScript
1
star
57

lerna-test

Shell
1
star
58

next-drupal-basic-starter

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

next-drupal-debug

JavaScript
1
star
60

teamworkpm

A node wrapper for the TeamworkPM API
JavaScript
1
star
61

imgs

www.imgs.io
1
star
62

twig_not_empty

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

gatsby-example-phoenix

Example site for @arshad/gatsby-theme-phoenix
JavaScript
1
star
64

wp-gatsby-extended

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

adminify

Simplify the Drupal admin
1
star
66

gatsby-theme-phoenix-disqus

Gatsby theme with Disqus
JavaScript
1
star
67

radix_layouts

Responsive Panels layouts for Radix.
PHP
1
star
68

Tray

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

next-drupal-auth

TypeScript
1
star