or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

graphql-resolvers.mdimage-cdn-polyfill.mdindex.mdjoi-schemas.mdruntime-compatibility.mdschema-validation.md
tile.json

image-cdn-polyfill.mddocs/

Image CDN Polyfill

Complete polyfill system for image CDN functionality, providing backward compatibility for remote file processing in older Gatsby versions with full GraphQL schema integration and HTTP route handling.

Capabilities

addRemoteFilePolyfillInterface

Adds RemoteFile interface to schema types, enabling remote file processing in Gatsby versions without native image CDN support.

/**
 * Adds RemoteFile interface polyfill to schema types
 * @param type - Schema type to enhance with RemoteFile interface
 * @param config - Configuration object with schema, actions, and store
 * @returns Enhanced type with RemoteFile interface
 */
function addRemoteFilePolyfillInterface<T>(
  type: T,
  config: {
    schema: SchemaBuilder;
    actions: Actions;
    store: Store;
  }
): T;

Usage Examples:

import { addRemoteFilePolyfillInterface } from "gatsby-plugin-utils/polyfill-remote-file";

exports.createSchemaCustomization = ({ actions, schema, store }) => {
  actions.createTypes([
    addRemoteFilePolyfillInterface(
      schema.buildObjectType({
        name: 'MyAsset',
        fields: {
          title: 'String!',
          description: 'String',
          url: 'String!',
          mimeType: 'String!'
        },
        interfaces: ['Node', 'RemoteFile']
      }),
      { schema, actions, store }
    )
  ]);
};

// For existing types
const MyImageType = schema.buildObjectType({
  name: 'MyImage',
  fields: {
    src: 'String!',
    alt: 'String',
    width: 'Int',
    height: 'Int'
  }
});

const enhancedType = addRemoteFilePolyfillInterface(MyImageType, {
  schema,
  actions, 
  store
});

polyfillImageServiceDevRoutes

Adds image service routes to development server for local image processing when native image CDN is not available.

/**
 * Adds image service routes for development server
 * @param app - Express application instance
 * @param store - Gatsby store instance (optional)
 */
function polyfillImageServiceDevRoutes(
  app: Application,
  store?: Store
): void;

Usage Examples:

import { polyfillImageServiceDevRoutes } from "gatsby-plugin-utils/polyfill-remote-file";

exports.onCreateDevServer = ({ app, store }) => {
  polyfillImageServiceDevRoutes(app, store);
};

// With feature detection
import { hasFeature } from "gatsby-plugin-utils";

exports.onCreateDevServer = ({ app, store }) => {
  if (!hasFeature('image-cdn')) {
    polyfillImageServiceDevRoutes(app, store);
  }
};

addImageRoutes

Manually adds file and image processing routes to Express application.

/**
 * Adds file and image processing routes to Express app
 * @param app - Express application instance  
 * @param store - Gatsby store instance (optional)
 * @returns Modified Express application
 */
function addImageRoutes(
  app: Application,
  store?: Store
): Application;

Usage Examples:

import { addImageRoutes } from "gatsby-plugin-utils/polyfill-remote-file";
import express from "express";

const app = express();
addImageRoutes(app, store);

// Available routes:
// GET /_gatsby/file/:url/:filename - Serves remote files
// GET /_gatsby/image/:url/:params/:filename - Serves processed images

isImageCdnEnabled

Checks if image CDN is enabled via environment variables.

/**
 * Checks if image CDN is enabled via environment variables
 * @returns Boolean indicating if image CDN is enabled
 */
function isImageCdnEnabled(): boolean;

Usage Examples:

import { isImageCdnEnabled } from "gatsby-plugin-utils/polyfill-remote-file";

if (isImageCdnEnabled()) {
  console.log("Using Gatsby Cloud Image CDN");
} else {
  console.log("Using local image processing");
}

// Environment variables that enable image CDN:
// GATSBY_CLOUD_IMAGE_CDN=1
// GATSBY_CLOUD_IMAGE_CDN=true

getRemoteFileFields

Returns GraphQL field definitions for remote file functionality.

/**
 * Returns remote file GraphQL field definitions
 * @param enums - Remote file enums for GraphQL types
 * @param actions - Gatsby actions
 * @param store - Gatsby store (optional)
 * @returns Object with field configurations
 */
function getRemoteFileFields(
  enums: RemoteFileEnums,
  actions: Actions,
  store?: Store
): {
  id: string;
  mimeType: string;
  filename: string;
  filesize: string;
  width: string;
  height: string;
  publicUrl: FieldConfig;
  resize: FieldConfig;
  gatsbyImage: FieldConfig;
};

Remote File Types

interface IRemoteFileNode extends Node {
  /** URL of the remote file */
  url: string;
  /** MIME type of the file */
  mimeType: string;
  /** Original filename */
  filename: string;
  /** File size in bytes (optional) */
  filesize?: number;
}

interface IRemoteImageNode extends IRemoteFileNode {
  /** Image width in pixels */
  width: number;
  /** Image height in pixels */
  height: number;
  /** Placeholder image URL (optional) */
  placeholderUrl?: string;
}

/**
 * Type guard to check if a remote file is an image
 * @param node - Remote file node to check
 * @returns Boolean indicating if node is an image
 */
function isImage(node: { mimeType: string }): node is IRemoteImageNode;

Image Processing Types

type ImageFormat = "jpg" | "png" | "webp" | "avif" | "auto";
type ImageLayout = "fixed" | "constrained" | "fullWidth";
type ImageCropFocus = 
  | "center" 
  | "top" 
  | "right" 
  | "bottom" 
  | "left" 
  | "entropy" 
  | "edges" 
  | "faces";

type ImageFit = 
  | "cover"
  | "contain" 
  | "fill"
  | "inside"
  | "outside";

interface WidthOrHeight {
  width?: number;
  height?: number;
}

interface CalculateImageSizesArgs extends WidthOrHeight {
  fit: ImageFit;
  layout: ImageLayout;
  outputPixelDensities: Array<number>;
  breakpoints?: Array<number>;
  aspectRatio?: number;
}

HTTP Routes

The polyfill system creates the following HTTP routes for image processing:

File Route

GET /_gatsby/file/:url/:filename
  • Serves remote files with proper headers
  • Handles caching and request headers
  • Supports all file types

Image Processing Route

GET /_gatsby/image/:url/:params/:filename
  • Processes images with specified parameters
  • Supports resize, format conversion, quality adjustment
  • Query parameters:
    • w - width
    • h - height
    • fm - format (jpg, png, webp, avif)
    • q - quality (1-100)

Complete Integration Example

// gatsby-node.js
const { hasFeature } = require("gatsby-plugin-utils");
const { addRemoteFilePolyfillInterface } = require("gatsby-plugin-utils/polyfill-remote-file");

exports.createSchemaCustomization = ({ actions, schema, store }) => {
  // Check if native image CDN is available
  if (hasFeature('image-cdn')) {
    // Use native RemoteFile interface
    actions.createTypes(`
      type Asset implements Node & RemoteFile {
        id: ID!
        title: String!
        url: String!
        mimeType: String!
        filename: String!
      }
    `);
  } else {
    // Use polyfill interface
    actions.createTypes([
      addRemoteFilePolyfillInterface(
        schema.buildObjectType({
          name: 'Asset',
          fields: {
            title: 'String!',
            url: 'String!',
            mimeType: 'String!', 
            filename: 'String!',
            description: 'String'
          },
          interfaces: ['Node', 'RemoteFile']
        }),
        { schema, actions, store }
      )
    ]);
  }
};

exports.onCreateDevServer = ({ app, store }) => {
  if (!hasFeature('image-cdn')) {
    const { polyfillImageServiceDevRoutes } = require("gatsby-plugin-utils/polyfill-remote-file");
    polyfillImageServiceDevRoutes(app, store);
  }
};

exports.sourceNodes = ({ actions, createNodeId, createContentDigest }) => {
  const { createNode } = actions;
  
  // Create asset nodes that will work with both native and polyfill
  const assets = [
    {
      title: "Hero Image",
      url: "https://example.com/hero.jpg",
      mimeType: "image/jpeg",
      filename: "hero.jpg"
    }
  ];
  
  assets.forEach(asset => {
    createNode({
      ...asset,
      id: createNodeId(`asset-${asset.title}`),
      parent: null,
      children: [],
      internal: {
        type: 'Asset',
        contentDigest: createContentDigest(asset)
      }
    });
  });
};

GraphQL Query Examples

With the polyfill in place, you can query remote files using standard GraphQL:

query {
  allAsset {
    nodes {
      id
      title
      url
      filename
      mimeType
      
      # Available through polyfill
      publicUrl
      
      # Image-specific fields (when applicable)
      gatsbyImage(width: 800, height: 600) {
        images {
          sources {
            srcSet
            type
          }
          fallback {
            src
            srcSet
          }
        }
        width
        height
      }
      
      resize(width: 400, height: 300) {
        src
        width
        height
      }
    }
  }
}

Error Handling

try {
  const enhancedType = addRemoteFilePolyfillInterface(type, config);
} catch (error) {
  console.error("Failed to add RemoteFile interface:", error);
  // Handle graceful degradation
}

// Route error handling
exports.onCreateDevServer = ({ app, store, reporter }) => {
  try {
    polyfillImageServiceDevRoutes(app, store);
    reporter.success("Image service routes added");
  } catch (error) {
    reporter.error("Failed to add image routes", error);
  }
};