egoist / mordred

[Experimental] Source data from anywhere, for Next.js, Nuxt.js, Eleventy and many more.
MIT License
205 stars 6 forks source link
inspired-by-gatsby nextjs nuxtjs react ssg ssr vue

ðŸĪš Mordred

npm version community

Source data from anywhere, for Next.js, Nuxt.js, Eleventy and many more.

Features

✅ Inspired by Gatsby, you can query any data (Markdown, API, database, CMS) with GraphQL
✅ Automatically generate JavaScript client for better dev experience
✅ Framework agnostic, works with any framework that has SSG support
✅ Tons of plugins for popular headless CMS (not yet, we need your contribution!)

Table of Contents

Install

yarn add mordred

Usage with Next.js

Configuration

In next.config.js:

const { withMordred } = require('mordred/next')

module.exports = withMordred({
  // Extra Next.js config..
})

Then create a mordred.config.js in the same directory and use some plugins:

module.exports = {
  plugins: [
    // Load markdown files from file system
    {
      resolve: 'mordred-source-filesystem',
      options: {
        // This is where you'll be creating Markdown files
        path: __dirname + '/content',
      },
    },
    // Transform files to markdown nodes
    {
      resolve: 'mordred-transformer-markdown',
    },
  ],
}

You also need to install these plugins:

yarn add mordred-source-filesystem mordred-transformer-markdown

Using Data

Create a Markdown file in content folder (in your project root), like content/my-first-posts.md:

---
title: My First Post
date: 2020-04-24
---

This is my **first** post!

When you run next or next build, Mordred will generate a GraphQL client at mordred/graphql.js, then you can use the generated client to query data.

You should add this folder to .gitignore:

mordred/

Now in any page, query data in getStaticProps:

import { client } from '../mordred/graphql'

export const getStaticProps = async () => {
  const { allMarkdown } = await client.query({
    allMarkdown: [
      {
        limit: 20
      },
      {
        nodes: {
          id: true,
          slug: true,
          createdAt: true,
          updatedAt: true,
          html: true,
          frontmatter {
            title: true
          }
        }
      }
    ]
  })
  return {
    props: {
      allMarkdown
    },
  }
}

export default ({ allMarkdown }) => {
  return (
    <ul>
      {allMarkdown.nodes.map((post) => {
        return (
          <li key={post.id}>
            <Link href={`/post/${post.slug}`}>{post.title}</Link>
          </li>
        )
      })}
    </ul>
  )
}

The client.query syntax is very similar to GraphQL SDL except that it also provides type hints as you write, we use graphql-zeus to generate the client code.

Execute Raw Query

If you prefer GraphQL SDL over the JavaScript client, you can execute raw query too:

import { executeQuery, gql } from './path/to/mordred/graphql'

const { data, errors } = await executeQuery(
  gql`
    query($limit: Int!) {
      allMarkdown(limit: $limit) {
        id
      }
    }
  `,
  {
    limit: 20,
  },
)

Note that we use the gql tag here only for syntax highlighting in supported editors like VS Code, it's completely optional.

Module Alias

When your project has a deep nested folder structure, you might run into import hell:

import { client } from '../../mordred/graphql'

To simplify the import path, you can use paths option in tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "mordred-graphql": ["./mordred/graphql"]
    }
  }
}

Now you can import form mordred-graphql instead.

Note that Next.js supports paths by default, but if you're using other tools which don't support this, you might find alias-hq helpful.

Exploring Data with GraphiQL

You can create an API at /api/graphql to explore data via GraphiQL:

import express from 'express'
import graphqlHTTP from 'express-graphql'
import { schema } from '../../mordred/graphql'

const app = express()

app.use(
  graphqlHTTP({
    schema,
    graphiql: true,
  }),
)

export default app

Plugin List

License

MIT © EGOIST (Kevin Titor)