Skip to content

Instantly share code, notes, and snippets.

@kmelve
Last active January 9, 2020 21:53
Show Gist options
  • Select an option

  • Save kmelve/0e4de671d08769cc7c60b948f7e15a29 to your computer and use it in GitHub Desktop.

Select an option

Save kmelve/0e4de671d08769cc7c60b948f7e15a29 to your computer and use it in GitHub Desktop.
RSS feed in Gatsby with Sanity as source
// Load variables from `.env` as soon as possible
require('dotenv').config({
path: `.env.${process.env.NODE_ENV || 'development'}`
})
const fetch = require('isomorphic-fetch')
const { createHttpLink } = require('apollo-link-http')
const PortableText = require('@sanity/block-content-to-html')
const imageUrlBuilder = require('@sanity/image-url')
const { isFuture } = require('date-fns')
const clientConfig = require('./client-config')
const {
getBlogUrl,
filterOutDocsPublishedInTheFuture
} = require('./helpers.js')
const h = PortableText.h
const isProd = process.env.NODE_ENV === 'production'
const imageUrlFor = source => imageUrlBuilder(clientConfig.sanity).image(source)
module.exports = {
siteMetadata: {
title: 'Knut Melvær',
siteUrl: 'https://www.knutmelvaer.no',
description: 'The blog and website of Knut Melvær'
},
plugins: [
'gatsby-plugin-postcss',
'gatsby-plugin-react-helmet',
{
resolve: 'gatsby-plugin-fathom',
options: {
// Fathom server URL. Defaults to `cdn.usefathom.com`
trackingUrl: 'stats.knutmelvaer.no',
// Unique site id
siteId: process.env.FATHOM_KEY
}
},
{
resolve: 'gatsby-source-graphql',
options: {
// This type will contain remote schema Query type
typeName: 'FATHOM',
// This is the field under which it's accessible
fieldName: 'fathom',
// URL to query from
createLink: () =>
createHttpLink({
uri: process.env.HASURA_GRAPHQL_ENDPOINT, // <- Configure connection GraphQL url
headers: {
'x-hasura-admin-secret': process.env.HASURA_ADMIN_SECRET
},
fetch
}),
refetchInterval: 10 // Refresh every 10 seconds for new data
}
},
{
resolve: 'gatsby-plugin-sitemap',
options: {
query: `
{
site {
siteMetadata {
siteUrl
}
}
allSitePage {
edges {
node {
id
path
context {
id
}
}
}
}
allSanityPost{
edges {
node {
id
publishedAt
}
}
}
}`,
serialize: ({ site, allSitePage, allSanityPost }) => {
// make a list of future posts
const futurePosts = [
...allSanityPost.edges.filter(({ node }) =>
isFuture(node.publishedAt)
)
// ...otherSanityType.edges.filter(({node})=> isFuture(node.publishedAt)),
]
const pagesInFuture = ({ node }) =>
futurePosts.find(({ node }) => node.id !== node.context.id)
return allSitePage.edges.filter(pagesInFuture).map(edge => {
return {
url: site.siteMetadata.siteUrl + edge.node.path,
changefreq: `daily`,
priority: 0.7
}
})
}
}
},
{
resolve: 'gatsby-source-sanity',
options: {
...clientConfig.sanity,
token: process.env.SANITY_READ_TOKEN,
watchMode: !isProd,
overlayDrafts: !isProd
}
},
{
resolve: `gatsby-plugin-webmention`,
options: {
username: 'www.knutmelvaer.no', // webmention.io username
identity: {
github: 'kmelve',
twitter: 'kmelve' // no @
},
mentions: true,
pingbacks: true,
// forwardPingbacksAsWebmentions: 'https://www.knutmelvaer.no/endpoint',
domain: 'www.knutmelvaer.no',
token: process.env.WEBMENTIONS_TOKEN
}
},
{
resolve: `gatsby-plugin-feed`,
options: {
query: `
{
site {
siteMetadata {
title
description
siteUrl
site_url: siteUrl
}
}
}
`,
feeds: [
{
serialize: ({ query: { site, allSanityPost = [] } }) => {
return allSanityPost.edges
.filter(({ node }) => filterOutDocsPublishedInTheFuture(node))
.filter(({ node }) => node.slug)
.map(({ node }) => {
const { title, publishedAt, slug, _rawBody } = node
const url =
site.siteMetadata.siteUrl +
getBlogUrl(publishedAt, slug.current)
return {
title: title,
date: publishedAt,
url,
guid: url,
custom_elements: [
{
'content:encoded':
_cdata: { PortableText({
blocks: _rawBody,
serializers: {
types: {
code: ({ node }) =>
h(
'pre',
h('code', { lang: node.language }, node.code)
),
mainImage: ({ node }) =>
h('img', {
src: imageUrlFor(node.asset).url()
}),
twitter: ({ node }) =>
h(
'p',
{},
h('a', {
href: node.url,
innerHTML: 'Look at the tweet.'
})
)
}
}
})
}
}
]
}
})
},
query: `{
allSanityPost(sort: {fields: publishedAt, order: DESC}) {
edges {
node {
_rawExcerpt
_rawBody(resolveReferences: {maxDepth: 10})
title
publishedAt
slug {
current
}
}
}
}
}
`,
output: '/rss.xml',
title: 'Knut Melvær'
// optional configuration to insert feed reference in pages:
// if `string` is used, it will be used to create RegExp and then test if pathname of
// current page satisfied this regular expression;
// if not provided or `undefined`, all pages will have feed reference inserted
}
]
}
}
]
}
const {format, isFuture} = require('date-fns')
function cn (...args) {
return args.filter(Boolean).join(' ')
}
function mapEdgesToNodes (data) {
if (!data.edges) return []
return data.edges.map(edge => edge.node)
}
function filterOutDocsWithoutSlugs ({slug}) {
return (slug || {}).current
}
function filterOutDocsPublishedInTheFuture({publishedAt}) {
return !isFuture(publishedAt)
}
function getBlogUrl (publishedAt, slug) {
return `/blog/${format(publishedAt, 'YYYY/MM')}/${slug.current || slug}/`
}
function buildImageObj (source) {
const imageObj = {
asset: {_ref: source.asset._ref || source.asset._id}
}
if (source.crop) imageObj.crop = source.crop
if (source.hotspot) imageObj.hotspot = source.hotspot
return imageObj
}
const defaults = {nonTextBehavior: 'remove'}
function toPlainText(blocks, opts = {}) {
const options = Object.assign({}, defaults, opts)
return blocks
.map(block => {
if (block._type !== 'block' || !block.children) {
return options.nonTextBehavior === 'remove' ? '' : `[${block._type} block]`
}
return block.children.map(child => child.text).join('')
})
.join('\n\n')
}
exports.cn = cn
exports.mapEdgesToNodes = mapEdgesToNodes
exports.filterOutDocsWithoutSlugs = filterOutDocsWithoutSlugs
exports.filterOutDocsPublishedInTheFuture = filterOutDocsPublishedInTheFuture
exports.getBlogUrl = getBlogUrl
exports.buildImageObj = buildImageObj
exports.toPlainText = toPlainText
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment