16

I have a website that I'm trying to optimize lighthouse page speed ranking. I just switched from SSR with nginx caching to next export using exportPathMap and getInitialProps (also with nginx caching).

Specific page of interest gets heavy traffic

After switching to static, the first content image appears loads in 2-2.5s for "slow 3G". However JS execution time takes like 3-6 seconds.

enter image description here

Questions:

  1. Why does script evaluation take 3-6s when I am using a static export, I was under the impression it would be quite fast?

  2. Are there ways to optimize nextjs JS execution time? Or maybe a webpack setting?

Kevin Danikowski
  • 4,620
  • 6
  • 41
  • 75
  • When I open that page with javascript disabled I do get all the content, scripts are loaded and executed before the user can interact with the page but all static html content seems to be there on initial load. – HMR May 12 '20 at 10:13
  • Maybe trying lazy import some modules that you know that could be really big so your users can have a lower script evaluation. I would also suggest some audits through profiling dev tools. – lndgalante May 13 '20 at 09:34
  • I assume this includes all the additional ad serving scripts right? – Samuel Goldenbaum May 13 '20 at 18:23
  • Yes this includes the ad serving scripts, those are going to slow the page, not much I can do about it. @HMR I did add lazy loading on everything but the rewriter section and it didn't make any different, I think it's just the rewriter section logic. I'll see if I can lazy load parts of it, not sure if lazy loading is supported for static export, worth looking into. – Kevin Danikowski May 14 '20 at 21:01
  • Want to try using lazyload? – Ozik Jarwo May 15 '20 at 02:37

2 Answers2

12

Try wrapping some heavy modules like this:

import dynamic from 'next/dynamic';
import { Spinner } from './spinner';

const MyLazyLoadedHeavyComponent = dynamic(() => import('./my-heavy-component'), {
  ssr: false,
  loading: () => <Spinner />
});

export const MyQuicklyLoadingPage: FC = () => {
  return (
    <div>
      <h1>Welcome to the page!</h1>
      <p>You'll see this text</p>
      <p>Before we load the heavy stuff below</p>
      <p>Large markdown files containing lots of images, etc.</p>
      <MyLazyLoadedHeavyComponent />
    </div>
  );
};

I also use this sometimes for modules that can't be rendered with SSR.

Also, evaluate whether something like attempting to use Preact will improve performance. I don't know how easy to do that is with nextJS. I found this https://github.com/developit/nextjs-preact-demo

  • 2
    Hey Charley, I accepted since the bounty only has 30 minutes left, but it doesn't actually help me too much. I've actually used this dynamic set up without success on 90% of the application, i'm going to attempt to use it on the 10% of the heavier part and see what happens. As for preact, I have considered, but I have some complex hook logic in some locations that I don't believe is supported from preact, specifically on one page. My pages are completely static and the logic is only run when you're using a text input area which shouldn't be too heavy. Any other suggestions are appreciated :) – Kevin Danikowski May 15 '20 at 14:37
  • Saddly I tried to improve it with this, and nothing :( I set most of the page to ssr false with next export without success :( It did reduce my JS size, but time didn't change much. – Kevin Danikowski May 19 '20 at 03:32
  • @KevinDanikowski did you find any solution for this issue? – MK Patel May 19 '21 at 09:39
  • @Mayank-Dolphin nope :/ I implemented static export without success. I haven't tried `useStaticProps` yet which I plan to try in the future. – Kevin Danikowski May 20 '21 at 01:31
  • What is `` referring to? – Steve Feb 22 '23 at 02:15
  • 1
    @Steve Its the loading state component. I renamed `` to `` to hopefully be more clear. – Honest Charley Bodkin Feb 22 '23 at 22:01
1

Have you tried this suggestion by Next.js? I think it's exactly your case.

<input
  type="text"
  placeholder="Country search..."
  className={styles.input}
  onChange={async e => {
    const { value } = e.currentTarget
    // Dynamically load libraries
    const Fuse = (await import('fuse.js')).default
    const _ = (await import('lodash')).default

    const fuse = new Fuse(countries, {
      keys: ['name'],
      threshold: 0.3
    })

    const searchResult = fuse.search(value).map(result => result.item)

    const updatedResults = searchResult.length ? searchResult : countries
    setResults(updatedResults)

    // Fake analytics hit
    console.info({
      searchedAt: _.now()
    })
  }}
/>
M G
  • 21
  • 3