Featured Images Not Loading on Home Page

Hello everyone,

I am getting this weird error where the featured images on the home page for the blog posts are not loading. The images will not load, though I have found that if I actually visit the blog posts the images will load. If I go back to the home screen, it will load the featured images all of a sudden.

It seems like an odd bug, and I am unsure whether it is simply my installation of Frontity, Zeit or Frontity itself causing the issue. Any help would be appreciated.

You can find my GitHub Repo at: https://github.com/Tikio88/Shaun-Guimond
The website is https://shaunguimond.com

Thank you in advance for any help!

Looking into it more, it seems like it may have something to do with the image.tsx in \[email protected]\components\image.tsx

I think the img tag is in the noscript tag which should switch with the placeholder img tag when the user gets to the image. It doesn’t seem to be working for some reason though.

Here is my version of the image.tsx:

    /* eslint-disable jsx-a11y/alt-text */

import React from "react";
import { Head, connect } from "frontity";
import { Connect, Package } from "frontity/types";
import useInView from "@frontity/hooks/use-in-view";

// Hides any image rendered by this component that is not
// inside a <noscript> when JS is disabled.
const noJsStyles = `
  :not(noscript) > .frontity-lazy-image {
    display: none;

// Finds all the images rendered by this component and maps
// their `data-src` and `data-srcset` attributes to `src` and `srcset`
// when the browser doesn't support Proxy or IntersectionObserver.
const noProxyScript = `
  if (typeof window !== "undefined" && (!("Proxy" in window) || !("IntersectionObserver" in window))) {
    document.addEventListener("DOMContentLoaded", function() {
      var images = document.querySelectorAll("img.frontity-lazy-image");
      for (i = 0; i < images.length; ++i) {
        var image = images[i];
        image.setAttribute("src", image.getAttribute("data-src"));
        image.setAttribute("srcset", image.getAttribute("data-srcset"));

interface Props {
  src?: string;
  srcSet?: string;
  sizes?: string;
  alt?: string;
  className?: string;
  rootMargin?: string;
  loading?: "auto" | "lazy" | "eager";
  height?: number;

type Image = React.FC<Connect<Package, Props>>;

interface Attributes extends Props {
  "data-src"?: string;
  "data-srcset"?: string;
  style?: { visibility: "hidden" };

type NoScriptImage = React.FC<Attributes>;

interface ChangeAttributes {
  (attrs: Attributes): Attributes;

const changeAttributes: ChangeAttributes = attrs => {
  const attributes = { ...attrs };

  attributes.src = attributes["data-src"];
  attributes.srcSet = attributes["data-srcset"];
  delete attributes["data-src"];
  delete attributes["data-srcset"];
  delete attributes["style"];

  return attributes;

const NoScriptImage: NoScriptImage = props => {
  const attributes = { ...props };

  return (
      <img {...attributes} />

const Image: Image = ({
  loading = "lazy",
}) => {
  // These are the attributes for the image when it's waiting to be loaded.
  const lazyAttributes: Attributes = {
    "data-src": src,
    "data-srcset": srcSet,
    className: "frontity-lazy-image".concat(className ? ` ${className}` : ""),
    style: { visibility: "hidden" },
  // These are the attributes for the image when it's loaded.
  const eagerAttributes = changeAttributes(lazyAttributes);

  // Renders a simple image, either in server or client, without
  // lazyload, if the loading attribute is set to `eager`.
  if (loading === "eager") {
    return <img {...eagerAttributes} />;

  // Changes the loading attribute to "auto" if loading is "lazy"
  // but there is no height specified (see https://crbug.com/954323)
  if (loading === "lazy" && !(height > 0)) {
    eagerAttributes.loading = "auto";
    lazyAttributes.loading = "auto";

  if (typeof window !== "undefined") {
    // Renders an image in client that will use IntersectionObserver to lazy load
    // if the native lazy load is not available,
    // or `height` prop is not provided.
    if (
      typeof IntersectionObserver !== "undefined" &&
      !("loading" in HTMLImageElement.prototype && height > 0)
    ) {
      const [onScreen, ref] = useInView({
        rootMargin: rootMargin,
        onlyOnce: true

      return (
          <NoScriptImage {...eagerAttributes} />
          <img ref={ref} {...(onScreen ? eagerAttributes : lazyAttributes)} />

    // Renders an image in client that will lazy load only if the native
    // lazy load is available, or load without lazy load otherwise.
    return (
        <NoScriptImage {...eagerAttributes} />
          {...(state.frontity.rendering === "csr"
            ? eagerAttributes
            : lazyAttributes)}

  // Renders an image in the server ready to work without JS,
  // without IntersectionObserver or without Proxy.
  return (
            id: "frontity-no-proxy-images",
            type: "text/javascript",
            innerHTML: noProxyScript
            innerHTML: `<style id="frontity-no-js-images" type="text/css">${noJsStyles}</style>`
      <NoScriptImage {...eagerAttributes} />
      <img {...lazyAttributes} />

export default connect(Image);

I’ll update once I find out more.

Excellent work porting the CSS to CSS-in-JS!

I’ve ported the changes to the official repo and with the help of @david we’ve ironed out other issues:

I’ve also added you as a contributor in the Readme.

This repository doesn’t include the other changes you made, like the comments or your footer, but could you please clone it in your local machine, change the api setting and see if featured images work?

I’ve tested it here and seems to be working fine.

I also recommend you to move your theme to the packages folder, instead of working in node_modules. Then add a .gitignore file and add both the folder build and node_modules. Then remove those files from the repo. Those shouldn’t be on git.
You can take a look at the official repo and copy that structure.

I also recommend you to update your now.json file to work with our new builder: https://docs.frontity.org/installation-and-deploy/deploy-on-now
With that builder you don’t need to have your build file committed in GitHub.

One you’ve done all that, I recommend you to start again from the official repo and add your footer and comments to that. It’s going to be easier. We will add a npx frontity update-package in the future to update local packages, but until then you can just copy and paste :slight_smile:

Last but not least, we’ve added a new setting state.theme.color which you can change to add your green back :shamrock:

Thanks sharing this excellent work @ShaGui!


Awesome! Glad to see the work that I did was useful for the original theme :slight_smile:

I will go ahead and test the repository and see if it fixes the featured image issues I am getting!

I will also make the changes to my repository. I am still learning Git so I appreciate the feedback!

Looking forward to the future updates and the new state.theme.color option!

Thank you so much @luisherranz :clap:


I want to take a moment and thank you again @luisherranz!

I went ahead and nuked my repository and reinstalled Frontity and the Twenty Nineteen theme. I just copied over my version of the theme into the packages and as soon as I did that and built to production the new install, the images began working. There must have been something wrong with my install of Frontity.

I also took your suggestion and corrected the structure of my Github repository.

I’m glad it works.

@david made more improvements on top your code, so I suggest you to take the new version of Twenty Nineteen as your new base and add your footer and comments components on top of that.

In that version, you can add your green color in the state.theme.color variable using for example frontity.settings.js and it should color all the links, menus and so on, just like you had it before.

Other than that, did you try the @frontity/now build? Did it work?

Very late on this, but I went ahead and did as you recommended. Thank you! I also used the new Now builder and it worked very well :clap:


Awesome! :smile: