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

ssr-apis.mddocs/

Server-Side Rendering APIs

Server-side plugin APIs for HTML generation, SEO optimization, and rendering customization through the gatsby-ssr.js file.

Capabilities

GatsbySSR Interface

Main interface for server-side rendering plugin APIs that control HTML generation, meta tags, and rendering customization.

/**
 * Main interface for gatsby-ssr.js plugin APIs
 */
interface GatsbySSR {
  /** Before HTML render */
  onPreRenderHTML?: (args: PreRenderHTMLArgs, pluginOptions?: PluginOptions) => void;
  /** Render body content */
  onRenderBody?: (args: RenderBodyArgs, pluginOptions?: PluginOptions) => void;
  /** Replace server renderer */
  replaceRenderer?: (args: ReplaceRendererArgs, pluginOptions?: PluginOptions) => void;
  /** Wrap page element */
  wrapPageElement?: (args: WrapPageElementNodeArgs, pluginOptions?: PluginOptions) => React.ReactElement;
  /** Wrap root element */
  wrapRootElement?: (args: WrapRootElementNodeArgs, pluginOptions?: PluginOptions) => React.ReactElement;
}

HTML Generation APIs

Control HTML document structure and content during server-side rendering.

/**
 * Pre-render HTML arguments
 */
interface PreRenderHTMLArgs {
  getHeadComponents: () => React.ReactElement[];
  replaceHeadComponents: (components: React.ReactElement[]) => void;
  getPreBodyComponents: () => React.ReactElement[];
  replacePreBodyComponents: (components: React.ReactElement[]) => void;
  getPostBodyComponents: () => React.ReactElement[];
  replacePostBodyComponents: (components: React.ReactElement[]) => void;
  pathname: string;
}

/**
 * Render body arguments
 */
interface RenderBodyArgs {
  setHeadComponents: (components: React.ReactElement[]) => void;
  setHtmlAttributes: (attributes: HtmlAttributes) => void;
  setBodyAttributes: (attributes: BodyAttributes) => void;
  setPreBodyComponents: (components: React.ReactElement[]) => void;
  setPostBodyComponents: (components: React.ReactElement[]) => void;
  setBodyProps: (props: object) => void;
  pathname: string;
}

interface HtmlAttributes {
  [key: string]: string | number | boolean;
}

interface BodyAttributes {
  [key: string]: string | number | boolean;
}

/**
 * Called before HTML rendering - modify components here
 */
onPreRenderHTML?: (args: PreRenderHTMLArgs, pluginOptions?: PluginOptions) => void;

/**
 * Called during HTML rendering - add components and attributes
 */
onRenderBody?: (args: RenderBodyArgs, pluginOptions?: PluginOptions) => void;

Usage Examples:

// gatsby-ssr.js - HTML generation
import React from "react";

exports.onRenderBody = ({
  setHtmlAttributes,
  setBodyAttributes,
  setHeadComponents,
  setPreBodyComponents,
  setPostBodyComponents,
  pathname,
}) => {
  // Set HTML lang attribute
  setHtmlAttributes({ lang: "en" });
  
  // Set body class based on page
  const bodyClass = pathname === "/" ? "home-page" : "inner-page";
  setBodyAttributes({ className: bodyClass });
  
  // Add meta tags and external resources
  setHeadComponents([
    <meta key="viewport" name="viewport" content="width=device-width, initial-scale=1" />,
    <meta key="theme-color" name="theme-color" content="#663399" />,
    <link key="preconnect-google" rel="preconnect" href="https://fonts.googleapis.com" />,
    <link
      key="google-fonts"
      rel="stylesheet"
      href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
    />,
  ]);
  
  // Add components before body content
  setPreBodyComponents([
    <div key="skip-nav" id="skip-nav">
      <a href="#main-content">Skip to main content</a>
    </div>,
  ]);
  
  // Add components after body content
  setPostBodyComponents([
    <script
      key="theme-script"
      dangerouslySetInnerHTML={{
        __html: `
          (function() {
            const theme = localStorage.getItem('theme') || 'light';
            document.documentElement.setAttribute('data-theme', theme);
          })();
        `,
      }}
    />,
  ]);
};

exports.onPreRenderHTML = ({
  getHeadComponents,
  replaceHeadComponents,
  getPostBodyComponents,
  replacePostBodyComponents,
  pathname,
}) => {
  // Remove unused CSS for production builds
  if (process.env.NODE_ENV === "production") {
    const headComponents = getHeadComponents();
    const filteredHeadComponents = headComponents.filter((component) => {
      // Remove unused stylesheets
      if (component.type === "style" && component.props.dangerouslySetInnerHTML) {
        const css = component.props.dangerouslySetInnerHTML.__html;
        return !css.includes(".unused-class");
      }
      return true;
    });
    replaceHeadComponents(filteredHeadComponents);
  }
  
  // Add analytics script for specific pages
  if (pathname.startsWith("/blog/")) {
    const postBodyComponents = getPostBodyComponents();
    replacePostBodyComponents([
      ...postBodyComponents,
      <script
        key="blog-analytics"
        dangerouslySetInnerHTML={{
          __html: `
            // Blog-specific analytics
            gtag('event', 'page_view', { page_path: '${pathname}' });
          `,
        }}
      />,
    ]);
  }
};

Element Wrapping APIs

Wrap page and root elements with custom server-side components.

/**
 * Wrap page element arguments (SSR)
 */
interface WrapPageElementNodeArgs {
  element: React.ReactElement;
  props: PageProps;
  pathname: string;
}

/**
 * Wrap root element arguments (SSR)  
 */
interface WrapRootElementNodeArgs {
  element: React.ReactElement;
  pathname: string;
}

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

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

Usage Examples:

// gatsby-ssr.js - Element wrapping
import React from "react";
import { Provider } from "react-redux";
import { ServerStyleSheet, StyleSheetManager } from "styled-components";
import { HelmetProvider } from "react-helmet-async";
import Layout from "./src/components/Layout";
import { createStore } from "./src/store";

// Wrap root with global providers for SSR
exports.wrapRootElement = ({ element, pathname }) => {
  // Create server-side store
  const store = createStore();
  
  // Helmet context for SSR
  const helmetContext = {};
  
  return (
    <Provider store={store}>
      <HelmetProvider context={helmetContext}>
        {element}
      </HelmetProvider>
    </Provider>
  );
};

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

// Handle styled-components SSR
exports.replaceRenderer = ({ bodyComponent, replaceBodyHTMLString, setHeadComponents }) => {
  const sheet = new ServerStyleSheet();
  
  try {
    const bodyHTML = ReactDOMServer.renderToString(
      sheet.collectStyles(bodyComponent)
    );
    
    replaceBodyHTMLString(bodyHTML);
    setHeadComponents([sheet.getStyleElement()]);
  } catch (error) {
    console.error("Error during SSR:", error);
  } finally {
    sheet.seal();
  }
};

Custom Renderer APIs

Replace the default server-side renderer with custom rendering logic.

/**
 * Replace renderer arguments
 */
interface ReplaceRendererArgs {
  bodyComponent: React.ReactElement;
  replaceBodyHTMLString: (html: string) => void;
  setHeadComponents: (components: React.ReactElement[]) => void;
  pathname: string;
}

/**
 * Replace the server-side renderer
 */
replaceRenderer?: (
  args: ReplaceRendererArgs,
  pluginOptions?: PluginOptions
) => void;

Usage Examples:

// gatsby-ssr.js - Custom renderer
import React from "react";
import ReactDOMServer from "react-dom/server";
import { ServerStyleSheet } from "styled-components";
import { ChunkExtractor } from "@loadable/server";

exports.replaceRenderer = ({
  bodyComponent,
  replaceBodyHTMLString,
  setHeadComponents,
  pathname,
}) => {
  // Handle styled-components
  const sheet = new ServerStyleSheet();
  
  // Handle loadable-components
  const extractor = new ChunkExtractor({
    statsFile: path.resolve("./public/loadable-stats.json"),
    entrypoints: ["app"],
  });
  
  try {
    // Wrap with providers
    const styledBody = sheet.collectStyles(bodyComponent);
    const loadableBody = extractor.collectChunks(styledBody);
    
    // Render to string
    const bodyHTML = ReactDOMServer.renderToString(loadableBody);
    
    // Replace body HTML
    replaceBodyHTMLString(bodyHTML);
    
    // Set head components
    const styleTags = sheet.getStyleElement();
    const linkTags = extractor.getLinkElements();
    const scriptTags = extractor.getScriptElements();
    
    setHeadComponents([...styleTags, ...linkTags, ...scriptTags]);
  } catch (error) {
    console.error("Custom renderer error:", error);
    // Fallback to default rendering
    const bodyHTML = ReactDOMServer.renderToString(bodyComponent);
    replaceBodyHTMLString(bodyHTML);
  } finally {
    sheet.seal();
  }
};

SEO and Meta Tags Management

Comprehensive SEO optimization through HTML manipulation.

Usage Examples:

// gatsby-ssr.js - SEO optimization
import React from "react";

exports.onRenderBody = ({ setHeadComponents, pathname }) => {
  // Dynamic meta tags based on page
  const getPageMeta = (pathname) => {
    const meta = {
      "/": {
        title: "Home - My Gatsby Site",
        description: "Welcome to my blazing fast Gatsby site",
        image: "/images/home-og.jpg",
      },
      "/about": {
        title: "About - My Gatsby Site", 
        description: "Learn more about our company and mission",
        image: "/images/about-og.jpg",
      },
    };
    
    return meta[pathname] || {
      title: "My Gatsby Site",
      description: "A blazing fast static site built with Gatsby",
      image: "/images/default-og.jpg",
    };
  };
  
  const pageMeta = getPageMeta(pathname);
  const siteUrl = "https://mysite.com";
  
  setHeadComponents([
    // Basic meta tags
    <title key="title">{pageMeta.title}</title>,
    <meta key="description" name="description" content={pageMeta.description} />,
    
    // Open Graph
    <meta key="og:type" property="og:type" content="website" />,
    <meta key="og:title" property="og:title" content={pageMeta.title} />,
    <meta key="og:description" property="og:description" content={pageMeta.description} />,
    <meta key="og:image" property="og:image" content={`${siteUrl}${pageMeta.image}`} />,
    <meta key="og:url" property="og:url" content={`${siteUrl}${pathname}`} />,
    
    // Twitter Card
    <meta key="twitter:card" name="twitter:card" content="summary_large_image" />,
    <meta key="twitter:title" name="twitter:title" content={pageMeta.title} />,
    <meta key="twitter:description" name="twitter:description" content={pageMeta.description} />,
    <meta key="twitter:image" name="twitter:image" content={`${siteUrl}${pageMeta.image}`} />,
    
    // Additional SEO
    <meta key="robots" name="robots" content="index,follow" />,
    <meta key="googlebot" name="googlebot" content="index,follow" />,
    <link key="canonical" rel="canonical" href={`${siteUrl}${pathname}`} />,
    
    // Performance hints
    <link key="dns-prefetch-google" rel="dns-prefetch" href="//fonts.googleapis.com" />,
    <link key="preconnect-google" rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />,
  ]);
};

Types

Core SSR Types

interface PageProps<
  DataType = object,
  PageContextType = object,
  LocationState = WindowLocation["state"],
  ServerDataType = object
> {
  data: DataType;
  location: WindowLocation<LocationState>;
  navigate: NavigateFn;
  pageContext: PageContextType;
  params: Record<string, string>;
  path: string;
  uri: string;
  pageResources: PageResources;
  serverData?: ServerDataType;
}

type NavigateFn = (
  to: string,
  options?: {
    replace?: boolean;
    state?: any;
  }
) => Promise<void>;

interface WindowLocation<S = unknown> {
  pathname: string;
  search: string;
  hash: string;
  href: string;
  origin: string;
  protocol: string;
  host: string;
  hostname: string;
  port: string;
  state: S;
  key?: string;
}

docs

browser-apis.md

components-hooks.md

configuration.md

graphql.md

index.md

node-apis.md

ssr-apis.md

tile.json