CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-gatsby

Blazing fast modern site generator for React with GraphQL data layer and plugin ecosystem

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

node-apis.mddocs/

Node.js APIs

Server-side APIs for plugin development, page creation, data sourcing, and build-time customization through the gatsby-node.js file.

Capabilities

GatsbyNode Interface

Main interface for build-time plugin APIs that control data sourcing, page creation, schema customization, and build configuration.

/**
 * Main interface for gatsby-node.js plugin APIs
 */
interface GatsbyNode {
  /** Plugin initialization */
  onPluginInit?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Before Gatsby initialization */
  onPreInit?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Before bootstrap phase */
  onPreBootstrap?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** After bootstrap phase */
  onPostBootstrap?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Before build phase */
  onPreBuild?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** After build phase */
  onPostBuild?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Before query extraction */
  onPreExtractQueries?: (args: ParentSpanPluginArgs) => Promise<void> | void;
  /** Create pages programmatically */
  createPages?: (args: CreatePagesArgs) => Promise<void> | void;
  /** Create pages with state management */
  createPagesStatefully?: (args: CreatePagesArgs) => Promise<void> | void;
  /** Modify created pages */
  onCreatePage?: (args: CreatePageArgs) => Promise<void> | void;
  /** Source nodes from external systems */
  sourceNodes?: (args: SourceNodesArgs) => Promise<void> | void;
  /** Process created nodes */
  onCreateNode?: (args: CreateNodeArgs) => Promise<void> | void;
  /** Filter node processing */
  shouldOnCreateNode?: (args: {
    node: Node;
  }, pluginOptions?: PluginOptions) => boolean;
  /** Customize GraphQL schema */
  createSchemaCustomization?: (args: CreateSchemaCustomizationArgs) => Promise<void> | void;
  /** Add GraphQL resolvers */
  createResolvers?: (args: CreateResolversArgs) => Promise<void> | void;
  /** Add fields to GraphQL node types */
  setFieldsOnGraphQLNodeType?: (args: SetFieldsOnGraphQLNodeTypeArgs) => object | Promise<object>;
  /** Modify Babel configuration */
  onCreateBabelConfig?: (args: CreateBabelConfigArgs) => Promise<void> | void;
  /** Modify Webpack configuration */
  onCreateWebpackConfig?: (args: CreateWebpackConfigArgs) => Promise<void> | void;
  /** Configure development server */
  onCreateDevServer?: (args: CreateDevServerArgs) => Promise<void> | void;
  /** Preprocess source files */
  preprocessSource?: (args: PreprocessSourceArgs) => Promise<string> | string;
  /** Add resolvable file extensions */
  resolvableExtensions?: (args: ParentSpanPluginArgs) => string[] | Promise<string[]>;
  /** Plugin options validation schema */
  pluginOptionsSchema?: (args: PluginOptionsSchemaArgs) => object;
}

Page Creation APIs

Create and manage pages programmatically during the build process.

/**
 * Create pages programmatically
 */
interface CreatePagesArgs extends ParentSpanPluginArgs {
  graphql: GraphQLFunction;
  actions: Actions;
  reporter: Reporter;
}

/**
 * GraphQL function for querying data during page creation
 */
type GraphQLFunction = <TData = any>(
  query: string,
  variables?: Record<string, any>
) => Promise<{
  errors?: any;
  data?: TData;
}>;

Usage Examples:

// gatsby-node.js
const path = require("path");

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions;

  // Query for blog posts
  const result = await graphql(`
    {
      allMarkdownRemark {
        edges {
          node {
            id
            frontmatter {
              slug
              title
            }
            html
          }
        }
      }
    }
  `);

  if (result.errors) {
    reporter.panicOnBuild("Error loading blog posts", result.errors);
    return;
  }

  // Create blog post pages
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: `/blog/${node.frontmatter.slug}`,
      component: path.resolve("./src/templates/blog-post.js"),
      context: {
        id: node.id,
        slug: node.frontmatter.slug,
      },
    });
  });

  // Create paginated blog index
  const posts = result.data.allMarkdownRemark.edges;
  const postsPerPage = 6;
  const numPages = Math.ceil(posts.length / postsPerPage);

  Array.from({ length: numPages }).forEach((_, i) => {
    createPage({
      path: i === 0 ? `/blog` : `/blog/${i + 1}`,
      component: path.resolve("./src/templates/blog-list.js"),
      context: {
        limit: postsPerPage,
        skip: i * postsPerPage,
        numPages,
        currentPage: i + 1,
      },
    });
  });
};

Data Sourcing APIs

Source and process data from external systems and files.

/**
 * Source nodes from external systems
 */
interface SourceNodesArgs extends ParentSpanPluginArgs {
  actions: Actions;
  createNodeId: CreateNodeIdFunction;
  createContentDigest: CreateContentDigestFunction;
  reporter: Reporter;
  getCache: GetCacheFunction;
  getNode: GetNodeFunction;
  getNodes: GetNodesFunction;
  hasNodeChanged: HasNodeChangedFunction;
  webhookBody?: object;
}

/**
 * Process created nodes
 */
interface CreateNodeArgs extends ParentSpanPluginArgs {
  node: Node;
  actions: Actions;
  createNodeId: CreateNodeIdFunction;
  createContentDigest: CreateContentDigestFunction;
  getNode: GetNodeFunction;
  getNodes: GetNodesFunction;
  reporter: Reporter;
}

type CreateNodeIdFunction = (input: string) => string;
type CreateContentDigestFunction = (input: string | object) => string;

Usage Examples:

// gatsby-node.js - Custom data source
exports.sourceNodes = async ({
  actions,
  createNodeId,
  createContentDigest,
  reporter,
}) => {
  const { createNode } = actions;

  try {
    // Fetch data from API
    const response = await fetch("https://api.example.com/posts");
    const posts = await response.json();

    // Create nodes for each post
    posts.forEach((post) => {
      const nodeId = createNodeId(`Post-${post.id}`);
      const nodeContent = JSON.stringify(post);

      const node = {
        ...post,
        id: nodeId,
        parent: null,
        children: [],
        internal: {
          type: "Post",
          content: nodeContent,
          contentDigest: createContentDigest(post),
        },
      };

      createNode(node);
    });

    reporter.info(`Created ${posts.length} Post nodes`);
  } catch (error) {
    reporter.panicOnBuild("Error sourcing posts from API", error);
  }
};

// Transform nodes after creation
exports.onCreateNode = ({ node, actions, createNodeId, createContentDigest }) => {
  const { createNode, createParentChildLink } = actions;

  // Process Markdown files
  if (node.internal.type === "MarkdownRemark") {
    // Extract reading time
    const readingTime = Math.ceil(node.rawMarkdownBody.split(" ").length / 200);

    // Create reading time node
    const readingTimeNode = {
      id: createNodeId(`ReadingTime-${node.id}`),
      parent: node.id,
      children: [],
      readingTime,
      text: `${readingTime} min read`,
      internal: {
        type: "ReadingTime",
        contentDigest: createContentDigest({ readingTime }),
      },
    };

    createNode(readingTimeNode);
    createParentChildLink({ parent: node, child: readingTimeNode });
  }
};

Schema Customization APIs

Define and customize the GraphQL schema for data querying.

/**
 * Customize GraphQL schema
 */
interface CreateSchemaCustomizationArgs extends ParentSpanPluginArgs {
  actions: Actions;
  schema: GatsbyGraphQLObjectType;
}

/**
 * Add GraphQL resolvers
 */
interface CreateResolversArgs extends ParentSpanPluginArgs {
  actions: Actions;
  schema: GatsbyGraphQLObjectType;
  createResolvers: CreateResolversFunction;
}

type CreateResolversFunction = (resolvers: Record<string, any>) => void;

Usage Examples:

// gatsby-node.js - Schema customization
exports.createSchemaCustomization = ({ actions, schema }) => {
  const { createTypes } = actions;

  // Define custom types
  const typeDefs = `
    type BlogPost implements Node {
      id: ID!
      title: String!
      slug: String!
      content: String!
      publishedAt: Date! @dateformat
      author: Author! @link(by: "id")
      tags: [Tag!]! @link(by: "name")
      featuredImage: File @fileByRelativePath
      readingTime: ReadingTime @link(by: "parent.id")
    }

    type Author implements Node {
      id: ID!
      name: String!
      email: String!
      bio: String
      avatar: File @fileByRelativePath
      posts: [BlogPost!]! @link(by: "author.id", from: "id")
    }

    type Tag implements Node {
      id: ID!
      name: String!
      slug: String!
      posts: [BlogPost!]! @link(by: "tags.name", from: "name")
    }
  `;

  createTypes(typeDefs);

  // Create field extension
  const slugify = (str) =>
    str
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, "-")
      .replace(/(^-|-$)+/g, "");

  createTypes(
    schema.buildObjectType({
      name: "BlogPost",
      fields: {
        slug: {
          type: "String!",
          resolve: (source) => slugify(source.title),
        },
      },
    })
  );
};

// Add custom resolvers
exports.createResolvers = ({ createResolvers }) => {
  const resolvers = {
    BlogPost: {
      relatedPosts: {
        type: ["BlogPost!"]!,
        resolve: async (source, args, context) => {
          const { entries } = await context.nodeModel.findAll({
            type: "BlogPost",
            query: {
              filter: {
                tags: { elemMatch: { name: { in: source.tags.map(t => t.name) } } },
                id: { ne: source.id },
              },
              limit: 3,
            },
          });
          return entries;
        },
      },
    },
    Author: {
      postCount: {
        type: "Int!",
        resolve: async (source, args, context) => {
          const { totalCount } = await context.nodeModel.findAll({
            type: "BlogPost",
            query: {
              filter: { author: { id: { eq: source.id } } },
            },
          });
          return totalCount;
        },
      },
    },
  };

  createResolvers(resolvers);
};

Build Configuration APIs

Customize Babel and Webpack configurations for the build process.

/**
 * Modify Webpack configuration
 */
interface CreateWebpackConfigArgs extends ParentSpanPluginArgs {
  stage: WebpackStage;
  rules: WebpackRules;
  loaders: WebpackLoaders;
  plugins: WebpackPlugins;
  actions: Actions;
}

type WebpackStage = 
  | "develop"
  | "develop-html" 
  | "build-javascript"
  | "build-html";

interface WebpackRules {
  js: () => object;
  eslint: () => object;
  yaml: () => object;
  fonts: () => object;
  images: () => object;
  media: () => object;
  miscAssets: () => object;
}

interface WebpackLoaders {
  json: () => object;
  yaml: () => object;
  null: () => object;
  raw: () => object;
  style: () => object;
  css: () => object;
  postcss: () => object;
  file: () => object;
  url: () => object;
  js: () => object;
  dependencies: () => object;
}

Usage Examples:

// gatsby-node.js - Webpack customization
exports.onCreateWebpackConfig = ({ stage, loaders, actions, plugins }) => {
  const { setWebpackConfig } = actions;

  // Add custom webpack configuration
  setWebpackConfig({
    resolve: {
      alias: {
        "@components": path.resolve(__dirname, "src/components"),
        "@utils": path.resolve(__dirname, "src/utils"),
        "@images": path.resolve(__dirname, "src/images"),
      },
    },
  });

  // Stage-specific configuration
  if (stage === "build-html" || stage === "develop-html") {
    setWebpackConfig({
      module: {
        rules: [
          {
            test: /canvas/,
            use: loaders.null(),
          },
        ],
      },
    });
  }

  // Add custom loader
  if (stage === "develop" || stage === "build-javascript") {
    setWebpackConfig({
      module: {
        rules: [
          {
            test: /\.md$/,
            use: [
              loaders.js(),
              {
                loader: "frontmatter-markdown-loader",
                options: { mode: ["body"] },
              },
            ],
          },
        ],
      },
    });
  }
};

// Babel configuration
exports.onCreateBabelConfig = ({ actions }) => {
  actions.setBabelPlugin({
    name: "@babel/plugin-proposal-export-default-from",
  });

  actions.setBabelPreset({
    name: "babel-preset-gatsby",
    options: {
      targets: {
        browsers: ["> 1%", "last 2 versions", "IE >= 9"],
      },
    },
  });
};

Actions API

Available actions for manipulating pages, nodes, and build configuration.

/**
 * Actions available in gatsby-node.js APIs
 */
interface Actions {
  /** Page management */
  createPage: (args: CreatePageArgs) => void;
  deletePage: (args: DeletePageArgs) => void;
  createSlice: (args: CreateSliceArgs) => void;
  
  /** Node management */
  createNode: (node: NodeInput) => void;
  deleteNode: (node: { id: string }) => void;
  touchNode: (node: { id: string }) => void;
  createNodeField: (args: CreateNodeFieldArgs) => void;
  createParentChildLink: (args: CreateParentChildLinkArgs) => void;
  
  /** Build configuration */
  setWebpackConfig: (config: object) => void;
  replaceWebpackConfig: (config: object) => void;
  setBabelOptions: (options: object) => void;
  setBabelPlugin: (args: SetBabelPluginArgs) => void;
  setBabelPreset: (args: SetBabelPresetArgs) => void;
  
  /** Schema management */
  createTypes: (typeDefs: string | object) => void;
  createFieldExtension: (args: CreateFieldExtensionArgs) => void;
  addThirdPartySchema: (args: AddThirdPartySchemaArgs) => void;
  printTypeDefinitions: (args: PrintTypeDefinitionsArgs) => void;
  
  /** Jobs and processing */
  createJob: (job: JobInput, plugin?: IGatsbyPlugin) => void;
  createJobV2: (job: JobV2Input, plugin?: IGatsbyPlugin) => void;
  setJob: (job: Job, plugin?: IGatsbyPlugin) => void;
  endJob: (job: Job, plugin?: IGatsbyPlugin) => void;
  
  /** Other actions */
  createRedirect: (redirect: RedirectInput) => void;
  setPluginStatus: (status: object, plugin?: IGatsbyPlugin) => void;
  setRequestHeaders: (headers: Record<string, string>) => void;
  addGatsbyImageSourceUrl: (url: string) => void;
  unstable_createNodeManifest: (args: CreateNodeManifestArgs) => void;
  addRemoteFileAllowedUrl: (url: string | RegExp) => void;
  enableStatefulSourceNodes: () => void;
}

Adapter System

Modern deployment adapter system for various hosting platforms.

/**
 * Adapter initialization function
 */
type AdapterInit = (options?: object) => IAdapter;

/**
 * Adapter interface for deployment platforms
 */
interface IAdapter {
  name: string;
  cache: Cache;
  config: IAdapterConfig;
  initializeAdapterStore?: () => Promise<void>;
  createRoutes?: (functions?: Array<IFunctionDefinition>) => Promise<RoutesManifest>;
}

interface IAdapterConfig {
  deployURL?: string;
  excludeDatastoreFromBundle?: boolean;
  imageCDN?: boolean;
  fileCDN?: boolean;
}

interface IFunctionDefinition {
  functionId: string;
  originalFilePath: string;
  relativeCompiledFilePath: string;
  absoluteCompiledFilePath: string;
  matches: Array<string>;
}

interface RoutesManifest {
  version: 1;
  routes: Array<IStaticRoute | IFunctionRoute | IRedirectRoute>;
  headers?: HeaderRoutes;
  functions?: FunctionsManifest;
}

docs

browser-apis.md

components-hooks.md

configuration.md

graphql.md

index.md

node-apis.md

ssr-apis.md

tile.json