gatsby-source-contentful
Version:
Gatsby source plugin for building websites using the Contentful CMS as a data source
118 lines (113 loc) • 3.96 kB
JavaScript
exports.__esModule = true;
exports.addNodeToExistingNodesCache = addNodeToExistingNodesCache;
exports.existingNodes = void 0;
exports.getExistingCachedNodes = getExistingCachedNodes;
exports.is = void 0;
exports.removeNodeFromExistingNodesCache = removeNodeFromExistingNodesCache;
var _index = require("gatsby-plugin-utils/index");
var _datastore = require("gatsby/dist/datastore");
var _utils = require("./utils");
// @ts-check
// Array of all existing Contentful nodes. Make it global and incrementally update it because it's hella slow to recreate this on every data update for large sites.
const existingNodes = new Map();
exports.existingNodes = existingNodes;
let allNodesLoopCount = 0;
// "is" === object so it can be overridden by tests
const is = {
firstSourceNodesCallOfCurrentNodeProcess: true
};
exports.is = is;
async function getExistingCachedNodes({
actions,
getNode,
pluginConfig
}) {
const {
touchNode
} = actions;
const needToTouchNodes = !(0, _index.hasFeature)(`stateful-source-nodes`) && is.firstSourceNodesCallOfCurrentNodeProcess;
if (existingNodes.size === 0) {
memoryNodeCountsBySysType.Asset = 0;
memoryNodeCountsBySysType.Entry = 0;
const dataStore = (0, _datastore.getDataStore)();
const allNodeTypeNames = Array.from(dataStore.getTypes());
for (const typeName of allNodeTypeNames) {
const typeNodes = dataStore.iterateNodesByType(typeName);
const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0];
if (!firstNodeOfType || firstNodeOfType.internal.owner !== `gatsby-source-contentful`) {
continue;
}
for (const node of typeNodes) {
if (needToTouchNodes) {
var _node$fields;
touchNode(node);
if (node !== null && node !== void 0 && (_node$fields = node.fields) !== null && _node$fields !== void 0 && _node$fields.includes(`localFile`)) {
// Prevent GraphQL type inference from crashing on this property
const fullNode = getNode(node.id);
const localFileNode = getNode(fullNode.fields.localFile);
touchNode(localFileNode);
}
}
if (++allNodesLoopCount % 5000 === 0) {
// dont block the event loop
await (0, _utils.untilNextEventLoopTick)();
}
addNodeToExistingNodesCache(node);
}
// dont block the event loop
await (0, _utils.untilNextEventLoopTick)();
}
}
is.firstSourceNodesCallOfCurrentNodeProcess = false;
return {
existingNodes,
memoryNodeCountsBySysType
};
}
const memoryNodeCountsBySysType = {
Asset: 0,
Entry: 0
};
// store only the fields we need to compare to reduce memory usage. if a node is updated we'll use getNode to grab the whole node before updating it
function addNodeToExistingNodesCache(node) {
if (node.internal.type === `ContentfulTag`) {
return;
}
if (node.sys.type in memoryNodeCountsBySysType && !existingNodes.has(node.id)) {
memoryNodeCountsBySysType[node.sys.type] ||= 0;
memoryNodeCountsBySysType[node.sys.type]++;
}
const cacheNode = {
id: node.id,
contentful_id: node.contentful_id,
sys: {
type: node.sys.type
},
node_locale: node.node_locale,
children: node.children,
internal: {
owner: node.internal.owner
},
__memcache: true
};
for (const key of Object.keys(node)) {
if (key.endsWith(`___NODE`)) {
cacheNode[key] = node[key];
}
}
existingNodes.set(node.id, cacheNode);
}
function removeNodeFromExistingNodesCache(node) {
if (node.internal.type === `ContentfulTag`) {
return;
}
if (node.sys.type in memoryNodeCountsBySysType && existingNodes.has(node.id)) {
memoryNodeCountsBySysType[node.sys.type] ||= 0;
memoryNodeCountsBySysType[node.sys.type]--;
if (memoryNodeCountsBySysType[node.sys.type] < 0) {
memoryNodeCountsBySysType[node.sys.type] = 0;
}
}
existingNodes.delete(node.id);
}
;