nicklima / strapi-blog-frontend-next

Frontend application of a Headless blog using Strapi as CMS
https://strapi-blog-frontend-next.vercel.app
MIT License
9 stars 1 forks source link

Improve scores on Google Lighthouse/PageSpeed #15

Open nicklima opened 2 years ago

nicklima commented 2 years ago

Issue #6 opened by @SoftCreatR, motivates me to try to improve the others' scores on Google LightHouse/PageSpeed

SoftCreatR commented 2 years ago

Did you test it? Because I can't see any differences:

image

image

Maybe not using Cloudinary, and just using Vercel instead does the trick? When doing so, you should consider using https://market.strapi.io/plugins/strapi-plugin-placeholder in Strapi and modify the ImageStrapi component accordingly:

import NextImage from "next/image"
import { getStrapiMedia } from "lib/media"
import { IStrapiImage } from "interfaces"

const ImageStrapi = ({
  image,
  layout,
  width,
  height,
  placeholder,
}: IStrapiImage) => {
  const { alternativeText } = image.data.attributes

  const imgSrc = getStrapiMedia(image)
  const imgW = width ? width : image.data.attributes.width
  const imgH = height ? height : image.data.attributes.height
  const blurDataURL = placeholder
    ? placeholder
    : image.data.attributes.placeholder

  const loader = () => `${imgSrc}?w=${imgW}&q=75`

  if (layout === "fill") {
    return (
      <NextImage
        loader={loader}
        layout="fill"
        objectFit="cover"
        src={imgSrc}
        alt={alternativeText || ""}
        placeholder="blur"
        blurDataURL={blurDataURL}
      />
    )
  }

  return (
    <NextImage
      loader={loader}
      layout={layout || "responsive"}
      width={imgW}
      height={imgH}
      objectFit="cover"
      src={imgSrc}
      alt={alternativeText || ""}
      placeholder="blur"
      blurDataURL={blurDataURL}
    />
  )
}

export default ImageStrapi

and

...

export interface IStrapiImage {
  image: {
    data: {
      attributes: any
    }
  }
  layout?: "responsive" | "fill" | "fixed" | "intrinsic" | undefined
  width?: string
  height?: string
  placeholder?: string
}

...

Oh, and you might check this out: https://web.dev/code-splitting-suspense/

Because unused Javascript currently takes 0.9 seconds, that could be saved. This tool could help here: https://github.com/vercel/next.js/tree/canary/packages/next-bundle-analyzer

You may also reduce the overall bundle size by moving the dependencies to devDependencies.

SoftCreatR commented 2 years ago

Follow up: If Vercel doesn't work as expected. this Strapi extension may help: https://market.strapi.io/plugins/strapi-plugin-local-image-sharp

nicklima commented 2 years ago

@SoftCreatR I had tested this with Google Lighthouse, and everything was fine. I will reopen this issue and check those points you mentioned. I'm using Heroku as a server for the Strapi application, and I don't know if it will work without an Image Provider (in this case, the Cloudinary).

By the way, thanks again for all the support. I will check the Bundle size problems and the code split link.

SoftCreatR commented 2 years ago

I don't know if it will work without an Image Provider

It does. The real question is if it works with Vercel only. Using Cloudinary is also problematic in connection with the GDPR, and IMHO, it shouldn't be a prerequisite for your application, so that it can be deployed with a single click (despite the environment setup).

SoftCreatR commented 2 years ago

I've just made some tests. The main problem is, that the image files are requested in the same (original) sizes (fixed width), but that makes not much sense. Instead, the width Parameter should change dynamically, but it doesn't.

EDIT:

Nvm, it seems to work in your demo now. However, it's still worth a try not to use Cloudinary at all. For Strapi, there's a module that should provide the same functionality: https://market.strapi.io/plugins/strapi-plugin-local-image-sharp

nicklima commented 2 years ago

Nvm, it seems to work in your demo now. However, it's still worth a try not to use Cloudinary at all. For Strapi, there's a module that should provide the same functionality: https://market.strapi.io/plugins/strapi-plugin-local-image-sharp

I'll check this later on Strapi. I'm reading and studying about the Dynamic import and trying to implement Bundle Analyzer with Next PWA in the next.js config file using next-compose-plugins.

SoftCreatR commented 2 years ago

I wonder, if this is still a thing: https://github.com/nicklima/strapi-blog-frontend-next/blob/main/pages/_app.tsx#L22-L40

nicklima commented 2 years ago

I wonder, if this is still a thing: https://github.com/nicklima/strapi-blog-frontend-next/blob/main/pages/_app.tsx#L22-L40

I was reading this TOPIC https://github.com/vercel/next.js/discussions/10949#discussioncomment-958694 to improve this point some days ago. If you have some ideas to fix, just tell me.

SoftCreatR commented 2 years ago

FYI: I found the reason, why the image component isn't working as expected (when not using Cloudinary).

The reason is this: https://github.com/nicklima/strapi-blog-frontend-next/blob/f2b1fa28a632cbe148f6a512ff8bfd59a14cb52a/components/ImageStrapi/index.tsx#L12

Instead of returning a string, you have to create a method:

  const loader = ({ src, width, quality, format }: IImageLoader) => {
    return `${imgSrc}?w=${width}&q=${quality || 75}&f=${format || 'webp'}`
  }

and provide the corresponding Interface:

export interface IImageLoader {
  src: string
  width?: number
  quality?: number
  format?: number
}

Otherwise, the width variable will be assigned, which always equals the the true image's width, which isn't what you want to achieve.

Now, you can set-up the Local Image Sharp plugin in Strapi, and you are ready to go.