Gatsby utils that help creating plugins
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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