diff --git a/packages/gatsby-source-contentful/src/gatsby-node.js b/packages/gatsby-source-contentful/src/gatsby-node.js index 5f83bc7996a96..079eb1a579bf5 100644 --- a/packages/gatsby-source-contentful/src/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/gatsby-node.js @@ -177,7 +177,13 @@ exports.sourceNodes = async ( }, pluginOptions ) => { - const { createNode, deleteNode, touchNode, createTypes } = actions + const { + createNode, + deleteNode, + touchNode, + createTypes, + unstable_createNodeManifest, + } = actions let currentSyncData let contentTypeItems @@ -672,6 +678,8 @@ exports.sourceNodes = async ( space, useNameForId: pluginConfig.get(`useNameForId`), pluginConfig, + syncToken, + unstable_createNodeManifest, }) ) } diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 82a31c9afadd7..1df8f93a8df1b 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -227,11 +227,89 @@ function prepareJSONNode(id, node, key, content) { return JSONNode } +let numberOfContentSyncDebugLogs = 0 +const maxContentSyncDebugLogTimes = 50 + +/** + * This fn creates node manifests which are used for Gatsby Cloud Previews via the Content Sync API/feature. + * Content Sync routes a user from Contentful to a page created from the entry data they're interested in previewing. + */ +function contentfulCreateNodeManifest({ + pluginConfig, + syncToken, + entryItem, + entryNode, + space, + unstable_createNodeManifest, +}) { + const isPreview = pluginConfig.get(`host`) === `preview.contentful.com` + + const createNodeManifestIsSupported = + typeof unstable_createNodeManifest === `function` + + const cacheExists = !!syncToken + + const shouldCreateNodeManifest = + isPreview && + createNodeManifestIsSupported && + // and this is a delta update + (cacheExists || + // or this entry/node was updated in the last 2 days. + // we don't want older nodes because we only want to create + // node manifests for recently updated/created content. + (entryItem.sys.updatedAt && + Date.now() - new Date(entryItem.sys.updatedAt).getTime() <= + // milliseconds + 1000 * + // seconds + 60 * + // minutes + 60 * + // hours + (Number( + process.env.CONTENT_SYNC_CONTENTFUL_HOURS_SINCE_ENTRY_UPDATE + ) || 48))) + + const manifestId = `${space.sys.id}-${entryItem.sys.id}-${entryItem.sys.updatedAt}` + + if ( + process.env.CONTENTFUL_DEBUG_NODE_MANIFEST === `true` && + numberOfContentSyncDebugLogs <= maxContentSyncDebugLogTimes + ) { + numberOfContentSyncDebugLogs++ + + console.info( + JSON.stringify({ + cacheExists, + isPreview, + createNodeManifestIsSupported, + shouldCreateNodeManifest, + manifestId, + entryItemSysUpdatedAt: entryItem.sys.updatedAt, + }) + ) + } + + if (shouldCreateNodeManifest) { + console.info(`Contentful: Creating node manifest with id ${manifestId}`) + + unstable_createNodeManifest({ + manifestId, + node: entryNode, + }) + } else if (isPreview && !createNodeManifestIsSupported) { + console.warn( + `Contentful: Your version of Gatsby core doesn't support Content Sync (via the unstable_createNodeManifest action). Please upgrade to the latest version to use Content Sync in your site.` + ) + } +} + exports.createNodesForContentType = ({ contentTypeItem, restrictedNodeFields, conflictFieldPrefix, entries, + unstable_createNodeManifest, createNode, createNodeId, getNode, @@ -241,6 +319,7 @@ exports.createNodesForContentType = ({ locales, space, useNameForId, + syncToken, pluginConfig, }) => { // Establish identifier for content type @@ -426,6 +505,15 @@ exports.createNodesForContentType = ({ }, } + contentfulCreateNodeManifest({ + pluginConfig, + syncToken, + entryItem, + entryNode, + space, + unstable_createNodeManifest, + }) + // Revision applies to entries, assets, and content types if (entryItem.sys.revision) { entryNode.sys.revision = entryItem.sys.revision