gatsby-source-sanity
Source plugin for pulling data from Sanity into Gatsby websites.
Basic usage
yarn add gatsby-source-sanity
# or
npm i gatsby-source-sanity --save
module.exports = {
plugins: [
{
resolve: 'gatsby-source-sanity',
options: {
projectId: '123456',
queries: [
{
name: 'posts',
type: 'Post',
groq: `
*[_type == 'post']{
_id,
title,
body,
}
`
},
{
name: 'authors',
groq: `*[_type == 'author']`
}
]
}
}
]
}
Go through http://localhost:8000/___graphql after running gatsby develop
to understand the created data and create a new query and checking available collections and fields by typing CTRL + SPACE
.
Options
Options | Type | Default | Description |
---|
projectId | string | | [required] Your Sanity project's ID |
dataset | string | production | The dataset to fetch from (can be tied to an .env file as needed) |
useCdn | boolean | true | Whether to use Sanity's CDN or not. Learn more |
saveImages | boolean | false | Whether to save images to disk. This has limitations, though. |
queries | array | | [required] An array of objects that should contain the options below: |
(Query object) name | string | | [required] The name of the query, vital for the plugin's functioning |
(Query object) groq | string | | [required] The actual GROQ query. |
(Query object) type | string | 'sanity' + query.name | Used to name the collection inside GraphQL |
PLEASE NOTE: All GROQ queries must contain the _id property as it'll be used as the internal ID for Gatsby's createNode
function. Your build process will fail otherwise.
Saving images to your filesystem
⚠️ This is an experimental feature, please report any bugs in the issues
If you want to save images to the filesystem, you can use the saveImages: true
option, but this will only work for those image objects containing a _type: 'image'
and an asset
property. The plugin uses the package @sanity/image-url
to create URLs for images that preserve hotspots, crops and so on. To avoid any errors in this process, the asset
field should, ideally, be complete.
Here's a quick way of building your queries with images that will be processed correctly:
Reminder: You can also serve images through Sanity.
const imageField = 'image{ _type, asset-> }';
const postsQuery = `
*[_type == 'post']{
_id,
meta{
${imageField},
},
author->{
name,
excerpt,
${imageField},
}
}
`;
Using .env variables
If you don't want to attach your Sanity project's ID to the repo, you can easily store it in .env files by doing the following:
SANITY_ID=123456
SANITY_DATASET=production
require("dotenv").config({
path: `.env.${process.env.NODE_ENV}`,
});
module.exports = {
plugins: [
{
resolve: 'gatsby-source-sanity',
options: {
projectId: process.env.SANITY_ID,
dataset: process.env.SANITY_DATASET,
}
}
]
}
This example is based off Gatsby Docs' implementation.
Storing your queries in an external file
Your GROQ queries will probably be long and complex, making it rather unruly to fit them all inside you gatsby-config.js
file. What I recommend doing is creating an external .js
file such as sanityQueries.js
and export your queries from there. Here's an example:
const metaQuery = `
meta {
"ogImage": ogImage.asset->.url,
seoDescription,
seoTitle,
slug,
title,
}
`;
const postsQuery = `
*[_type == 'post']{
${metaQuery.trim()},
_id,
body,
author,
}
`;
const authorsQuery = `
*[_type == 'author']{
_id,
name,
description,
"photo": headshot.asset->.url,
}
`;
module.exports = {
postsQuery,
authorsQuery,
}
const queries = require('./sanityNewQueries');
module.exports = {
plugins: [
{
resolve: 'gatsby-source-sanity',
options: {
queries: [
{
name: 'posts',
type: 'Post',
groq: queries.postsQuery,
},
{
name: 'authors',
type: 'Author',
groq: queries.authorsQuery,
}
]
}
}
]
}
Plugin's shortcomings
Sanity is an API builder, and for such, it's extremely hard to predict its data model: you can have all sorts of data types, with fields nested 8 levels deep inside an object, for example. For such, this plugin can't go far in shaping your nodes' format.
If you need extra or modified fields built right into the nodes, your option is to process them in your gatsby-node.js
file through the onCreateNode API.
Please note: Gatsby's createNodeField
action attaches your new field inside a fields
object in your node, so when you query for your data in GraphQL, you'll have to do so by calling fields { [FIELD-NAME] }
. I recommend that you play around with GraphiQl to understand the data format before building your front-end.
Attaching a custom field to created nodes
The example below is for creating a slug field for your nodes.
const slugify = require('slugify');
exports.onCreateNode = ({ node, actions }) => {
const { createNodeField } = actions;
if (node.internal.type === 'Post') {
createNodeField({
node,
name: 'slug',
value: slugify(node.title, { lower: true })
})
}
}
Serving images through Sanity
Alternatively, you can use Sanity's image-url library and fetch images on the clientside through their urlFor
function, that is quite powerful in transforming the files.
Then you can LazyLoad these images and manipulate them to the client's device and connection through the urlFor
function's parameter. More info on this, visit the package's npm page.
The downside of this approach is that you'd have to create lazy-loading components yourself (or use one from the community), and not have the magical blur / traced-SVG effect of the gatsby-image
plugin.
TODO
- Do a regEx test for the query names and types to avoid errors from Gatsby
- Test for bugs in different environments and data structures (I have not tested this with Gatsby v1 or v0, yet!)
- Better asset pipeline (I've tried setting up Typescript and file bundling to no avail, if you can help out with this, it'd be awesome!)
- Gather feedback for new functionalities if needed
Credits
First and foremost, a huge thanks to the good people backing Sanity for bringing such a joy to my developer life with this amazing CMS.
As for the image-saving functionality, it was inspired heavily, at points copied, by Nectum at his gatsby-source-test implementation.