FastBuilds support and webhook handling for efficient development workflows, incremental content updates, and preview functionality.
Enables incremental builds by fetching only changed content since the last build, dramatically reducing build times for large sites.
/**
* FastBuilds configuration option
* Requires the gatsby_fastbuilds Drupal module and user permissions
*/
fastBuilds: boolean;FastBuilds process:
lastFetched timestamp from plugin statuslastFetched timestamp for next buildUsage Examples:
{
resolve: `gatsby-source-drupal`,
options: {
baseUrl: `https://your-site.com/`,
basicAuth: {
username: process.env.BASIC_AUTH_USERNAME,
password: process.env.BASIC_AUTH_PASSWORD,
},
fastBuilds: true, // Requires authentication and Drupal module
},
}Processes webhook updates for real-time content synchronization during development and preview.
/**
* Handles webhook updates for incremental content changes
* @param gatsbyApi - Gatsby API functions and webhook data
* @param pluginOptions - Plugin configuration options
* @returns Promise that resolves when update is processed
*/
function handleWebhookUpdate(
gatsbyApi: {
nodeToUpdate: DrupalEntity;
actions: {
createNode: Function;
unstable_createNodeManifest: Function;
};
cache: Cache;
createNodeId: Function;
createContentDigest: Function;
getCache: Function;
getNode: Function;
reporter: Reporter;
},
pluginOptions: PluginOptions
): Promise<void>;
interface WebhookBody {
secret?: string;
action: 'insert' | 'update' | 'delete';
data: DrupalEntity | DrupalEntity[];
}Usage Examples:
// Webhook handling is automatic when webhookBody is present
// Configure webhook secret for security:
{
resolve: `gatsby-source-drupal`,
options: {
baseUrl: `https://your-site.com/`,
secret: process.env.PREVIEW_SECRET, // Must match Drupal configuration
},
}
// Webhook request format from Drupal:
{
"secret": "your-shared-secret",
"action": "update",
"data": {
"id": "article-123",
"type": "node--article",
"attributes": { /* updated content */ },
"relationships": { /* entity relationships */ }
}
}Manages node deletion and relationship cleanup when content is removed from Drupal.
/**
* Handles deletion of nodes and cleanup of relationships
* @param options - Configuration for deletion handling
* @returns Promise resolving to the deleted node
*/
function handleDeletedNode(options: {
actions: Actions;
node: DrupalEntity;
getNode: Function;
createNodeId: Function;
createContentDigest: Function;
cache: Cache;
entityReferenceRevisions: string[];
pluginOptions: PluginOptions;
}): Promise<GatsbyNode>;The deletion process:
Enables Gatsby Preview integration for content editors and development workflows.
/**
* Creates node manifests for Gatsby Cloud Preview support
* @param options - Manifest creation configuration
*/
function drupalCreateNodeManifest(options: {
attributes: DrupalEntityAttributes;
gatsbyNode: GatsbyNode;
unstable_createNodeManifest: Function;
}): void;Usage Examples:
// Preview is automatically enabled in development with refresh endpoint
process.env.NODE_ENV === 'development' &&
process.env.ENABLE_GATSBY_REFRESH_ENDPOINT
// Or explicitly enabled with:
process.env.GATSBY_IS_PREVIEW === 'true'Ensures referenced nodes exist before processing relationships, creating missing nodes as needed.
/**
* Creates node if it doesn't exist (for webhook updates and references)
* @param options - Node creation configuration
* @returns Promise that resolves when node is created or already exists
*/
function createNodeIfItDoesNotExist(options: {
nodeToUpdate: DrupalEntity;
actions: Actions;
createNodeId: Function;
createContentDigest: Function;
getNode: Function;
reporter: Reporter;
pluginOptions: PluginOptions;
}): Promise<void>;This ensures referential integrity when:
gatsby_fastbuilds moduleThe plugin queries the FastBuilds endpoint:
GET /gatsby-fastbuilds/sync/{timestamp}Response format:
{
"status": 1,
"timestamp": 1623456789,
"entities": [
{
"action": "update",
"data": { /* entity data */ }
},
{
"action": "delete",
"data": { "id": "node-123", "type": "node--article" }
}
]
}// Expired or missing timestamp
if (res.body.status === -1) {
reporter.info('Unable to pull incremental data changes from Drupal');
setPluginStatus({ lastFetched: res.body.timestamp });
requireFullRebuild = true;
}
// Network or API errors trigger full rebuild
catch (error) {
reporter.warn('FastBuilds request failed, falling back to full build');
requireFullRebuild = true;
}For development, the plugin provides webhook endpoints for live updates:
// Legacy endpoint (deprecated)
app.use('/___updatePreview/', bodyParser.text(), async (req, res) => {
// Handle preview updates
});
// Modern approach uses Gatsby's refresh endpoint
// Configure in Drupal to POST to: http://localhost:8000/__refreshImplement webhook security with shared secrets:
// Validate webhook secret
if (pluginOptions.secret && pluginOptions.secret !== secret) {
reporter.warn('The secret in this request did not match your plugin options secret.');
return;
}
// Validate webhook structure
if (!action || !data) {
reporter.warn('The webhook body was malformed');
return;
}Handle multiple entity updates in a single webhook:
// Webhook can contain single entity or array
let nodesToUpdate = data;
if (!Array.isArray(data)) {
nodesToUpdate = [data];
}
// Process each entity
for (const nodeToUpdate of nodesToUpdate) {
await handleWebhookUpdate(/* ... */);
}During FastBuilds, existing nodes are "touched" to prevent garbage collection:
// Touch existing nodes during incremental builds
getNodes().forEach(node => {
if (node.internal.owner === 'gatsby-source-drupal') {
touchNode(node);
}
});Relationships are cached to optimize processing:
// Cache referenced nodes
await cache.set(`refnodes-${node.id}`, referencedNodes);
// Cache back-reference field names
await cache.set(`backrefs-${node.id}`, backRefsNames);Updates are processed with configurable concurrency:
// Process multiple webhook updates concurrently
await Promise.all(nodesToUpdate.map(async (nodeToUpdate) => {
await handleWebhookUpdate(/* ... */);
}));When using Gatsby Cloud, the plugin creates node manifests for Content Sync:
// Manifest creation for preview routing
const manifestId = `${id}-${updatedAt}-${langcode}`;
unstable_createNodeManifest({
manifestId,
node: gatsbyNode,
updatedAtUTC: updatedAt,
});Content Sync uses manifests to route editors from Drupal to the correct preview pages, enabling seamless editorial workflows.
interface WebhookBody {
secret?: string;
action: 'insert' | 'update' | 'delete';
data: DrupalEntity | DrupalEntity[];
}
interface FastBuildsResponse {
status: number; // 1 for success, -1 for expired/error
timestamp: number;
entities: FastBuildsEntity[];
}
interface FastBuildsEntity {
action: 'insert' | 'update' | 'delete';
data: DrupalEntity | { id: string; type: string };
}
interface NodeManifestOptions {
manifestId: string;
node: GatsbyNode;
updatedAtUTC: string;
}