CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-gatsby-plugin-utils

Gatsby utils that help creating plugins

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

runtime-compatibility.mddocs/

Runtime Compatibility

Runtime detection system for Gatsby node lifecycle APIs and feature availability, enabling plugins to support multiple Gatsby versions gracefully.

Capabilities

isGatsbyNodeLifecycleSupported

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
  };
}

hasFeature

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
}

Supported Lifecycle APIs

Common Gatsby node lifecycle APIs that can be checked:

  • createSchemaCustomization - Modern GraphQL schema customization
  • createResolvers - Custom GraphQL resolvers
  • sourceNodes - Source node creation
  • onCreateNode - Node creation hooks
  • createPages - Page creation API
  • onPreBootstrap - Pre-bootstrap lifecycle
  • createPagesStatefully - Stateful page creation
  • preprocessSource - Source preprocessing
  • resolvableExtensions - File extension resolution
  • setFieldsOnGraphQLNodeType - Legacy field customization

Feature Detection

Available features that can be detected:

type AvailableFeatures = 
  | "image-cdn"
  | "graphql-typegen" 
  | "tracing"
  | "webpack-5"
  | "fast-refresh"
  | "incremental-builds"
  | "parallel-sourcing";

Error Handling

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
}

Version-Safe Plugin Development

// 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;

Best Practices

  1. Always wrap in try-catch: Version detection can fail on very old Gatsby versions
  2. Graceful degradation: Provide fallbacks when features aren't available
  3. Feature-first development: Use hasFeature() to enable optimal paths when available
  4. Conditional exports: Only export lifecycle APIs that are supported
  5. User communication: Inform users about version compatibility requirements

docs

graphql-resolvers.md

image-cdn-polyfill.md

index.md

joi-schemas.md

runtime-compatibility.md

schema-validation.md

tile.json