Runtime detection system for Gatsby node lifecycle APIs and feature availability, enabling plugins to support multiple Gatsby versions gracefully.
Checks if a specific Gatsby node lifecycle API is supported in the current Gatsby version.
/**
* Checks if a Gatsby node lifecycle API is supported
* @param apiName - Name of the lifecycle API to check
* @returns Boolean indicating if the API is available
* @throws Error if gatsby version is incompatible (< 2.13.41)
*/
function isGatsbyNodeLifecycleSupported(apiName: string): boolean;Usage Examples:
import { isGatsbyNodeLifecycleSupported } from "gatsby-plugin-utils";
// Check for modern schema customization API
if (isGatsbyNodeLifecycleSupported('createSchemaCustomization')) {
exports.createSchemaCustomization = ({ actions, schema }) => {
actions.createTypes(schema.buildObjectType({
name: 'MyCustomType',
fields: {
id: 'ID!',
title: 'String!'
}
}));
};
} else {
// Fall back to older setFieldsOnGraphQLNodeType API
exports.setFieldsOnGraphQLNodeType = ({ type }) => {
if (type.name === 'MyCustomType') {
return {
customField: {
type: 'String',
resolve: (source) => source.title
}
};
}
};
}
// Check for newer lifecycle APIs
if (isGatsbyNodeLifecycleSupported('createResolvers')) {
exports.createResolvers = (resolvers) => {
// Use modern resolver API
};
}
if (isGatsbyNodeLifecycleSupported('sourceNodes')) {
exports.sourceNodes = async ({ actions, createNodeId, createContentDigest }) => {
// Create source nodes
};
}Checks if a specific Gatsby feature is available in the current version.
/**
* Checks if a Gatsby feature is available
* @param name - Feature name to check for availability
* @returns Boolean indicating if the feature is available
* @throws Error if gatsby version is incompatible (< 2.13.41)
*/
function hasFeature(name: AvailableFeatures): boolean;Usage Examples:
import { hasFeature } from "gatsby-plugin-utils";
// Check for image CDN support
if (hasFeature('image-cdn')) {
// Use native Gatsby image CDN
console.log("Using native image CDN");
} else {
// Use polyfill functionality
console.log("Using image CDN polyfill");
const { addRemoteFilePolyfillInterface } = require("gatsby-plugin-utils/polyfill-remote-file");
// Setup polyfill...
}
// Check for other features
if (hasFeature('graphql-typegen')) {
// Use GraphQL type generation features
} else {
// Handle without type generation
}
if (hasFeature('tracing')) {
// Enable performance tracing
}
if (hasFeature('webpack-5')) {
// Use Webpack 5 specific features
}Common Gatsby node lifecycle APIs that can be checked:
createSchemaCustomization - Modern GraphQL schema customizationcreateResolvers - Custom GraphQL resolverssourceNodes - Source node creationonCreateNode - Node creation hookscreatePages - Page creation APIonPreBootstrap - Pre-bootstrap lifecyclecreatePagesStatefully - Stateful page creationpreprocessSource - Source preprocessingresolvableExtensions - File extension resolutionsetFieldsOnGraphQLNodeType - Legacy field customizationAvailable features that can be detected:
type AvailableFeatures =
| "image-cdn"
| "graphql-typegen"
| "tracing"
| "webpack-5"
| "fast-refresh"
| "incremental-builds"
| "parallel-sourcing";Both functions will throw an error if the Gatsby version is too old:
try {
const isSupported = isGatsbyNodeLifecycleSupported('createSchemaCustomization');
} catch (error) {
// Error: Couldn't check available APIs. Make sure you are on gatsby version >=2.13.41
console.error("Gatsby version too old:", error.message);
// Handle graceful degradation
}
try {
const hasImageCdn = hasFeature('image-cdn');
} catch (error) {
// Error: Couldn't check available APIs. Make sure you are on gatsby version >=2.13.41
console.error("Feature detection unavailable:", error.message);
// Assume feature is not available
}// gatsby-node.js
const { isGatsbyNodeLifecycleSupported, hasFeature } = require("gatsby-plugin-utils");
// Conditional exports based on API availability
const nodeApis = {};
// Always available in modern Gatsby
nodeApis.onPreInit = async ({ reporter }) => {
reporter.info("Plugin initializing...");
};
// Conditionally export based on API support
if (isGatsbyNodeLifecycleSupported('createSchemaCustomization')) {
nodeApis.createSchemaCustomization = ({ actions, schema }) => {
// Modern schema API
actions.createTypes(`
type MyNode implements Node {
id: ID!
title: String!
slug: String!
}
`);
};
}
if (isGatsbyNodeLifecycleSupported('createResolvers')) {
nodeApis.createResolvers = (resolvers) => {
resolvers.MyNode = {
slug: {
resolve: (source) => source.title.toLowerCase().replace(/\s+/g, '-')
}
};
};
}
// Feature-based conditional logic
if (hasFeature('image-cdn')) {
nodeApis.onCreateNode = ({ node, actions }) => {
// Use native image CDN processing
};
} else {
// Use polyfill or alternative approach
const { addRemoteFilePolyfillInterface } = require("gatsby-plugin-utils/polyfill-remote-file");
nodeApis.createSchemaCustomization = ({ actions, schema, store }) => {
actions.createTypes([
addRemoteFilePolyfillInterface(
schema.buildObjectType({
name: 'MyImageNode',
fields: {
url: 'String!',
alt: 'String'
},
interfaces: ['Node', 'RemoteFile']
}),
{ schema, actions, store }
)
]);
};
}
// Export conditionally created APIs
module.exports = nodeApis;hasFeature() to enable optimal paths when available