or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

browser-apis.mdcomponents-hooks.mdconfiguration.mdgraphql.mdindex.mdnode-apis.mdssr-apis.md
tile.json

browser-apis.mddocs/

Browser APIs

Client-side plugin APIs for handling routing, service workers, rendering customization, and user interactions through the gatsby-browser.js file.

Capabilities

GatsbyBrowser Interface

Main interface for client-side plugin APIs that control browser behavior, routing, rendering, and user interactions.

/**
 * Main interface for gatsby-browser.js plugin APIs
 */
interface GatsbyBrowser {
  /** Client-side entry point */
  onClientEntry?: (args?: object, pluginOptions?: PluginOptions) => void;
  /** Initial client render complete */
  onInitialClientRender?: (args?: object, pluginOptions?: PluginOptions) => void;
  /** Route change occurred */  
  onRouteUpdate?: (args: RouteUpdateArgs, pluginOptions?: PluginOptions) => void;
  /** Before route change */
  onPreRouteUpdate?: (args: RouteUpdateArgs, pluginOptions?: PluginOptions) => void;
  /** Delayed route update */
  onRouteUpdateDelayed?: (args: RouteUpdateDelayedArgs, pluginOptions?: PluginOptions) => void;
  /** Disable core prefetching */
  disableCorePrefetching?: (args?: object, pluginOptions?: PluginOptions) => boolean;
  /** Before prefetch pathname */
  onPrefetchPathname?: (args: PrefetchPathnameArgs, pluginOptions?: PluginOptions) => void;
  /** After prefetch pathname */
  onPostPrefetchPathname?: (args: PrefetchPathnameArgs, pluginOptions?: PluginOptions) => void;
  /** Register service worker */
  registerServiceWorker?: (args?: object, pluginOptions?: PluginOptions) => boolean;
  /** Service worker active */
  onServiceWorkerActive?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;
  /** Service worker installed */
  onServiceWorkerInstalled?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;
  /** Service worker redundant */
  onServiceWorkerRedundant?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;
  /** Service worker update found */
  onServiceWorkerUpdateFound?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;
  /** Service worker update ready */
  onServiceWorkerUpdateReady?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;
  /** Replace hydrate function */
  replaceHydrateFunction?: () => (element: React.ReactElement, container: Element, callback?: () => void) => void;
  /** Control scroll behavior */
  shouldUpdateScroll?: (args: ShouldUpdateScrollArgs, pluginOptions?: PluginOptions) => boolean | string | [number, number];
  /** Wrap page element */
  wrapPageElement?: (args: WrapPageElementBrowserArgs, pluginOptions?: PluginOptions) => React.ReactElement;
  /** Wrap root element */
  wrapRootElement?: (args: WrapRootElementBrowserArgs, pluginOptions?: PluginOptions) => React.ReactElement;
}

Client Lifecycle APIs

Handle client-side initialization and rendering lifecycle events.

/**
 * Client entry point - called when the app first loads
 */
onClientEntry?: (args?: object, pluginOptions?: PluginOptions) => void;

/**
 * Initial client render complete - called after React hydration
 */
onInitialClientRender?: (args?: object, pluginOptions?: PluginOptions) => void;

/**
 * Replace the default React hydrate function
 */
replaceHydrateFunction?: () => (
  element: React.ReactElement,
  container: Element,
  callback?: () => void
) => void;

Usage Examples:

// gatsby-browser.js - Client lifecycle
exports.onClientEntry = () => {
  // Initialize analytics
  if (typeof window !== "undefined" && window.gtag) {
    window.gtag("config", "GA_MEASUREMENT_ID");
  }
  
  // Load polyfills
  if (!window.IntersectionObserver) {
    import("intersection-observer");
  }
};

exports.onInitialClientRender = () => {
  // Set up global event listeners
  document.addEventListener("visibilitychange", () => {
    if (document.hidden) {
      console.log("Page is hidden");
    } else {
      console.log("Page is visible");
    }
  });
  
  // Initialize third-party libraries
  if (typeof window !== "undefined" && window.Prism) {
    window.Prism.highlightAll();
  }
};

// Custom hydration for React 18
exports.replaceHydrateFunction = () => {
  return (element, container, callback) => {
    const { hydrateRoot } = require("react-dom/client");
    hydrateRoot(container, element);
    if (callback) callback();
  };
};

Routing APIs

Handle navigation, route changes, and prefetching behavior.

/**
 * Route update arguments
 */
interface RouteUpdateArgs {
  location: WindowLocation;
  prevLocation?: WindowLocation;
}

/**
 * Delayed route update arguments  
 */
interface RouteUpdateDelayedArgs {
  location: WindowLocation;
  prevLocation?: WindowLocation;
}

/**
 * Called on every route change
 */
onRouteUpdate?: (args: RouteUpdateArgs, pluginOptions?: PluginOptions) => void;

/**
 * Called before route change
 */
onPreRouteUpdate?: (args: RouteUpdateArgs, pluginOptions?: PluginOptions) => void;

/**
 * Called when route update is delayed
 */
onRouteUpdateDelayed?: (args: RouteUpdateDelayedArgs, pluginOptions?: PluginOptions) => void;

Usage Examples:

// gatsby-browser.js - Route handling
exports.onRouteUpdate = ({ location, prevLocation }) => {
  // Track page views
  if (typeof window !== "undefined" && window.gtag) {
    window.gtag("config", "GA_MEASUREMENT_ID", {
      page_location: window.location.href,
      page_path: location.pathname,
    });
  }
  
  // Close mobile menu on navigation
  const mobileMenu = document.querySelector(".mobile-menu");
  if (mobileMenu && mobileMenu.classList.contains("open")) {
    mobileMenu.classList.remove("open");
  }
  
  // Scroll to top on new page
  if (prevLocation && location.pathname !== prevLocation.pathname) {
    window.scrollTo(0, 0);
  }
};

exports.onPreRouteUpdate = ({ location }) => {
  // Show loading indicator
  const loader = document.querySelector(".page-loader");
  if (loader) {
    loader.style.display = "block";
  }
};

exports.onRouteUpdateDelayed = ({ location }) => {
  // Handle slow navigation
  console.log("Route update delayed for:", location.pathname);
  
  // Show network error message
  const errorMsg = document.querySelector(".network-error");
  if (errorMsg) {
    errorMsg.style.display = "block";
  }
};

Prefetching APIs

Control and customize resource prefetching behavior.

/**
 * Prefetch pathname arguments
 */
interface PrefetchPathnameArgs {
  pathname: string;
  loadableReady?: Promise<void>;
}

/**
 * Disable core prefetching - return true to disable
 */
disableCorePrefetching?: (args?: object, pluginOptions?: PluginOptions) => boolean;

/**
 * Called before prefetching pathname
 */
onPrefetchPathname?: (args: PrefetchPathnameArgs, pluginOptions?: PluginOptions) => void;

/**
 * Called after prefetching pathname
 */
onPostPrefetchPathname?: (args: PrefetchPathnameArgs, pluginOptions?: PluginOptions) => void;

Usage Examples:

// gatsby-browser.js - Prefetching
exports.disableCorePrefetching = () => {
  // Disable prefetching on slow connections
  return (
    typeof navigator !== "undefined" &&
    navigator.connection &&
    (navigator.connection.effectiveType === "slow-2g" ||
     navigator.connection.effectiveType === "2g")
  );
};

exports.onPrefetchPathname = ({ pathname }) => {
  console.log("Prefetching:", pathname);
  
  // Custom prefetch logic
  if (pathname.startsWith("/blog/")) {
    // Prefetch blog-specific assets
    const link = document.createElement("link");
    link.rel = "prefetch";
    link.href = "/assets/blog-styles.css";
    document.head.appendChild(link);
  }
};

exports.onPostPrefetchPathname = ({ pathname, loadableReady }) => {
  console.log("Prefetched:", pathname);
  
  // Track prefetch completion
  if (typeof window !== "undefined" && window.gtag) {
    window.gtag("event", "prefetch_complete", {
      page_path: pathname,
    });
  }
};

Service Worker APIs

Handle service worker lifecycle and events.

/**
 * Service worker arguments
 */
interface ServiceWorkerArgs {
  serviceWorker?: ServiceWorker;
}

/**
 * Register service worker - return true to register
 */
registerServiceWorker?: (args?: object, pluginOptions?: PluginOptions) => boolean;

/**
 * Service worker became active
 */
onServiceWorkerActive?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;

/**
 * Service worker was installed
 */
onServiceWorkerInstalled?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;

/**
 * Service worker became redundant
 */
onServiceWorkerRedundant?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;

/**
 * Service worker update found
 */
onServiceWorkerUpdateFound?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;

/**
 * Service worker update ready
 */
onServiceWorkerUpdateReady?: (args: ServiceWorkerArgs, pluginOptions?: PluginOptions) => void;

Usage Examples:

// gatsby-browser.js - Service Worker
exports.registerServiceWorker = () => {
  // Only register in production
  return process.env.NODE_ENV === "production";
};

exports.onServiceWorkerActive = () => {
  console.log("Service worker is active");
  
  // Show app ready message
  const updateBanner = document.querySelector(".update-banner");
  if (updateBanner) {
    updateBanner.textContent = "App is ready for offline use";
    updateBanner.classList.add("show");
    setTimeout(() => updateBanner.classList.remove("show"), 3000);
  }
};

exports.onServiceWorkerUpdateReady = () => {
  console.log("Service worker update ready");
  
  // Show update available message
  const updateBanner = document.querySelector(".update-banner");
  if (updateBanner) {
    updateBanner.innerHTML = `
      <div>
        New version available!
        <button onclick="window.location.reload()">Update</button>
      </div>
    `;
    updateBanner.classList.add("show");
  }
};

exports.onServiceWorkerUpdateFound = () => {
  console.log("Service worker update found");
  
  // Show downloading message
  const updateBanner = document.querySelector(".update-banner");
  if (updateBanner) {
    updateBanner.textContent = "Downloading update...";
    updateBanner.classList.add("show");
  }
};

Scroll Management APIs

Control scroll behavior during navigation.

/**
 * Scroll update arguments
 */
interface ShouldUpdateScrollArgs {
  routerProps: {
    location: WindowLocation;
    navigate: NavigateFn;
  };
  getSavedScrollPosition: (location: WindowLocation) => [number, number] | null;
}

/**
 * Control scroll behavior on navigation
 * @returns boolean - true to update scroll, false to prevent
 * @returns string - element selector to scroll to
 * @returns [number, number] - x,y coordinates to scroll to
 */
shouldUpdateScroll?: (
  args: ShouldUpdateScrollArgs,
  pluginOptions?: PluginOptions
) => boolean | string | [number, number];

Usage Examples:

// gatsby-browser.js - Scroll management
exports.shouldUpdateScroll = ({ routerProps, getSavedScrollPosition }) => {
  const { location } = routerProps;
  
  // Don't scroll on hash changes
  if (location.hash) {
    return false;
  }
  
  // Restore saved position for browser back/forward
  const savedPosition = getSavedScrollPosition(location);
  if (savedPosition) {
    return savedPosition;
  }
  
  // Custom scroll behavior for specific routes
  if (location.pathname.startsWith("/docs/")) {
    // Scroll to top for docs pages
    return [0, 0];
  }
  
  if (location.pathname.startsWith("/blog/")) {
    // Preserve scroll position for blog
    return false;
  }
  
  // Default behavior - scroll to top
  return true;
};

Element Wrapping APIs

Wrap page and root elements with custom components.

/**
 * Wrap page element arguments (browser)
 */
interface WrapPageElementBrowserArgs {
  element: React.ReactElement;
  props: PageProps;
}

/**
 * Wrap root element arguments (browser)
 */
interface WrapRootElementBrowserArgs {
  element: React.ReactElement;
}

/**
 * Wrap each page with custom elements
 */
wrapPageElement?: (
  args: WrapPageElementBrowserArgs,
  pluginOptions?: PluginOptions
) => React.ReactElement;

/**
 * Wrap the root element
 */
wrapRootElement?: (
  args: WrapRootElementBrowserArgs,
  pluginOptions?: PluginOptions
) => React.ReactElement;

Usage Examples:

// gatsby-browser.js - Element wrapping
import React from "react";
import { Provider } from "react-redux";
import { ThemeProvider } from "styled-components";
import Layout from "./src/components/Layout";
import store from "./src/store";
import theme from "./src/theme";

// Wrap root with global providers
exports.wrapRootElement = ({ element }) => (
  <Provider store={store}>
    <ThemeProvider theme={theme}>
      {element}
    </ThemeProvider>
  </Provider>
);

// Wrap each page with layout
exports.wrapPageElement = ({ element, props }) => (
  <Layout {...props}>
    {element}
  </Layout>
);