Collected Notes + Gatsby
Previously I made a starter template joining 11ty and collected notes, here's the post, this time, I wanted to try it out with Gatsby, I ended up building two things, a gatsby starter and a gatsby source plugin.
You could do this in a single project but I wanted to try and make my own separate plugin
Setup
Luckily gatsby has great docs, so, I followed these instructions.
First our repo for the starter:
gatsby new gatsby-starter-collected-notes https://github.com/gatsbyjs/gatsby-starter-hello-world
Then the repo for the source plugin:
gatsby new gatsby-source-collected-notes https://github.com/gatsbyjs/gatsby-starter-plugin
Source plugin
From the plugin starter template, I removed all the other gatsby files but the gatsby-node.js and index.js.
const axios = require("axios");
const POST_NODE_TYPE = `CollectedNote`;
exports.sourceNodes = async ({
actions,
createContentDigest,
createNodeId,
}, { notesOwner }) => {
const { createNode } = actions;
// Call the Collceted Notes API with the passed in notesOwner
const result = await axios.get(`https://collectednotes.com/${notesOwner}.json`);
if (result.status !== 200)
throw new Error("Could not fetch notes from collected notes API");
result.data.notes.forEach((note) =>
createNode({
...note,
id: createNodeId(`${POST_NODE_TYPE}-${note.id}`),
internal: {
type: POST_NODE_TYPE,
contentDigest: createContentDigest(note),
},
})
);
return;
};
This is basically it, remember to install axios if you are following along (or the library that you prefer).
Starter template
The important part here is to
- Install your source plugin and require it on the gatsby-config.js, I actually published gatsby-source-collected-notes to npm but you can require it like
plugins: [
{
resolve: `gatsby-source-collected-notes`,
options: {
notesOwner: "jenaro", //the aprameter we passed in the plugin
},
}
],
- Create pages on gatsby-node.js
const path = require("path")
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
// We have our data available on the graphql layer because of our plugin
const result = await graphql(
`
query CollectedNotesQuery {
allCollectedNote {
nodes {
path
}
}
}
`
)
// Handle errors
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`)
return
}
// post template to use.
const blogPostTemplate = path.resolve(`src/templates/blog-post.js`)
// Create pages for each note.
result.data.allCollectedNote.nodes.forEach(node => {
const path = node.path
createPage({
path: `/blog/${path}`,
component: blogPostTemplate,
// this context is later passed in to the template
context: {
pagePath: path,
},
})
})
}
- Lastly the post template that I defined on
src/templates/blog-post.js
import React from "react"
import ReactMarkdown from "react-markdown"
import { graphql } from "gatsby"
import Layout from "../components/Layout"
import SEO from "../components/SEO"
// here pagePath is exposed to the template because we defined it in the context.
export const query = graphql`
query NoteQuery($pagePath: String!) {
collectedNote(path: { eq: $pagePath }) {
body
created_at
curated
headline
id
path
poster
site_id
title
updated_at
url
user_id
visibility
}
}
`
const BlogPost = ({ data, location }) => {
if (!data) return null
const note = data.collectedNote
return (
<Layout pathname={location.pathname}>
<SEO description={note.headline} title={note.title} bodyClass="post" />
{/* Remember to include this dependency to be able to render the markdown appropiately */}
<ReactMarkdown source={note.body} />
</Layout>
)
}
export default BlogPost
And that's basically it! There you go once more, easy peasy, you got your CMS with Collected Notes and Gatsby, everything else on this template is styling or easy enough to follow along.
You can find the repositories at:
- https://github.com/jenaro94/gatsby-source-collected-notes
- https://github.com/jenaro94/gatsby-starter-collected-notes
Demo at https://gatsbynotes.netlify.app