Ускорение производительности Gatsby

На работе мне дали задание повысить производительность моего проекта. В настоящее время оценка Google Lighthouse колеблется, но в целом она не так хороша, поэтому мы пытаемся выяснить, как повысить ее производительность, чтобы иметь возможность похвастаться нашим руководством.

Наш проект загружает весь сайт Gatsby как единый пакет JavaScript. Это создает на сайте одностраничное приложение, которое позволяет быстро загружать новые страницы с помощью JavaScript. Но с такими большими сайтами, как наши сайты WordPress, получается очень большой пакет в мегабайтах. Этот большой пакет значительно снижает скорость загрузки страницы.

Я не совсем уверен, как справиться с разгрузкой этого bundle.js, но нашел интересный документ на эту тему https://www.gatsbyjs.org/docs/how-code-splitting-works/

Хотя я не совсем понимаю эти документы, но я считаю, что редактирую этот файл async-requires.js, чтобы включить несколько строк компонентов экспорта, и это должно привести к созданию нескольких пакетов javascript вместо основного большого. Возможно, если существует несколько пакетов js, сайт будет загружаться быстрее, потому что он не ограничен одним. Таким образом, страница может загружаться в конкретном пакете, который ей нужен для рендеринга, и асинхронно загружать тот, который ей не нужен.

Ниже приведен код, который, как мне кажется, относится к поставленной задаче. Я все еще немного новичок, когда дело доходит до Гэтсби, поэтому я не совсем уверен, что я могу изменить здесь, чтобы обеспечить лучшую производительность.

Спасибо вам за помощь.

async-requires.js

const preferDefault = m => m && m.default || m

exports.components = {
  "component---src-templates-page-js": () => import("../src/templates/page.js" /* webpackChunkName: "component---src-templates-page-js" */),
  "component---cache-dev-404-page-js": () => import("dev-404-page.js" /* webpackChunkName: "component---cache-dev-404-page-js" */),
  "component---src-pages-404-js": () => import("../src/pages/404.js" /* webpackChunkName: "component---src-pages-404-js" */)
}

SRC / шаблоны / pages.js

import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import Layout from '../layouts/layout'
import AnalyticsContext, { analyticsEvents } from '../../util/AnalyticsContext'

import Banner from '../WPComponents/Banner'
import CheckmarkList from '../WPComponents/CheckmarkList'
import CopyGrid from '../WPComponents/CopyGrid'
import Drawers from '../WPComponents/Drawers'
import Explainers from '../WPComponents/Explainers'
import Featured from '../WPComponents/Featured'
import Form from '../WPComponents/Form'
import Hero from '../WPComponents/Hero'
import Pricing from '../WPComponents/Pricing'
import PromoApp from '../WPComponents/PromoApp'
import PromoCircles from '../WPComponents/PromoCircles'
import PromoSlider from '../WPComponents/PromoSlider'
import ReachAnimation from '../WPComponents/ReachAnimation'
import Resources from '../WPComponents/Resources'
import SimpleExplainer from '../WPComponents/SimpleExplainer'
import SimpleMedia from '../WPComponents/SimpleMedia'
import Solution from '../WPComponents/Solution'
import Testimonials from '../WPComponents/Testimonials'
import Disclaimer from '../WPComponents/Disclaimer'

const PageTemplate = props => {
  const { pageContext, data, location } = props
  const components = (pageContext.acf && pageContext.acf.section_page) || []
  let helmet
  const { yoast } = pageContext

  if (yoast) {
    const {
      title,
      metadesc,
      opengraph_title,
      opengraph_description,
      opengraph_image,
      canonical,
    } = yoast

    helmet = (
      <Helmet
        title={title || ' '}
        meta={[
          {
            name: 'robots',
            content: 'noindex',
          },
          {
            name: 'description',
            content: metadesc || ' ',
          },
          {
            property: 'og:title',
            content: opengraph_title || ' ',
          },
          { property: 'og:site_name', content: title || ' ' },
          { property: 'og:type', content: 'website' },
          {
            property: 'og:description',
            content: opengraph_description || ' ',
          },
          {
            property: 'og:image',
            content: opengraph_image && opengraph_image.source_url,
          },
          canonical
            ? {
                property: 'og:url',
                content: canonical || ' ',
              }
            : {},
        ]}
      />
    )
  }

  return (
    <AnalyticsContext.Provider
      value={{
        ...analyticsEvents,
      }}
    >
      <Layout location={location}>
        {helmet}
        {components.map(component => {
          switch (component.__typename) {
            case 'WordPressAcf_hero':
              return <Hero key={component.id} {...component} />
            case 'WordPressAcf_featured':
              return <Featured key={component.id} {...component} />
            case 'WordPressAcf_solution':
              return <Solution key={component.id} {...component} />
            case 'WordPressAcf_resources':
              return <Resources key={component.id} {...component} />
            case 'WordPressAcf_simplemedia':
              return <SimpleMedia key={component.id} {...component} />
            case 'WordPressAcf_promoapp':
              return <PromoApp key={component.id} {...component} />
            case 'WordPressAcf_reach_animation':
              return <ReachAnimation key={component.id} {...component} />
            case 'WordPressAcf_promoslider':
              return <PromoSlider key={component.id} {...component} />
            case 'WordPressAcf_promocircles':
              return <PromoCircles key={component.id} {...component} />
            case 'WordPressAcf_testimonials':
              return <Testimonials key={component.id} {...component} />
            case 'WordPressAcf_banner':
              return <Banner key={component.id} {...component} />
            case 'WordPressAcf_explainers':
              return <Explainers key={component.id} {...component} />
            case 'WordPressAcf_copygrid':
              return <CopyGrid key={component.id} {...component} />
            case 'WordPressAcf_drawers':
              return <Drawers key={component.id} {...component} />
            case 'WordPressAcf_simpleexplainer':
              return <SimpleExplainer key={component.id} {...component} />
            case 'WordPressAcf_disclaimer':
              return <Disclaimer key={component.id} {...component} />
            case 'WordPressAcf_pricing':
              return (
                <Pricing key={component.id} {...component} /> 
              )
            case 'WordPressAcf_checkmarklist':
              return <CheckmarkList key={component.id} {...component} />
            case 'WordPressAcf_form':
              return <Form key={component.id} {...component} />
            default:
              console.log('Could not recongize type:', component.__typename)
              return
          }
        })}
      </Layout>
    </AnalyticsContext.Provider>
  )
}

PageTemplate.propTypes = {
  pageContext: PropTypes.shape({
    acf: PropTypes.object,
    media: PropTypes.shape({
      edges: PropTypes.array,
    }),
  }),
}

export default PageTemplate

pageCreators.js

const path = require('path')
const genericPageTemplate = 'src/templates/page.js'

const pageCreator = templatePath => (actions, pageContext) => {

  actions.createPage({
    component: path.resolve(templatePath),
    path: pageContext.pagePath,
    context: {
      ...pageContext,
    },
  })
}

module.exports = {
  createGenericPage: pageCreator(genericPageTemplate),
}

createPages.js

const { createGenericPage } = require('./pageCreators')

const generatePages = allWordpressPage => {
  return allWordpressPage.edges.map(edge => edge.node)
}

module.exports = (data, actions) => {
  if (!data) {
    console.error('createPages()', 'Error', '`data` is undefined')
    throw new Error('Error retrieving data: data is undefined')
  }

  const { allWordpressPage } = data

  const pages = allWordpressPage && generatePages(allWordpressPage)

  if (!pages) {
    console.error(
      'createPages()',
      'Error',
      'Could not build pages. allWordpressPage was falsy'
    )
    throw new Error('Error retreiving data: allWordpressPage was falsy')
  }

  pages &&
    pages.forEach(page => {

      // skip the 'modules' page
      if (page.pagePath === '/modules/') {
        return;
      }

      createGenericPage(actions, page)
    })
}

gatsby-node.js

/**
 * Implement Gatsby's Node APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/node-apis/
 */

const fs = require('fs')

const queryAll = require('./util/queryAll')
const createPages = require('./util/createPages')

exports.createPages = ({ graphql, actions }) => {
  return graphql(queryAll)
    .then(res => {
      if (res.errors) {
        res.errors.forEach(error => {
          console.error('Error:', error.message)
        })
      }

      createPages(res.data, actions)
    })
    .catch(error => {
      console.error('failed to create pages:', { error })
    })
}

exports.sourceNodes = ({ actions, schema }) => {
  const { createTypes } = actions

  const additionalTypeDefs = fs.readFileSync(`type-defs.gql`, {
    encoding: `utf-8`,
  })
  createTypes(additionalTypeDefs)
}

// temporary fix for dev env: https://github.com/gatsbyjs/gatsby/issues/11934#issuecomment-469046186
exports.onCreateWebpackConfig = ({ getConfig, stage }) => {
  const config = getConfig()
  if (stage.startsWith('develop') && config.resolve) {
    config.resolve.alias = {
      ...config.resolve.alias,
      'react-dom': '@hot-loader/react-dom',
    }
  }
}

person Eric Lima    schedule 04.02.2020    source источник
comment
Не могли бы вы поделиться чем, например, developers.google.com/speed/pagespeed/insights говорит про сайт?   -  person Patrik Rikama-Hinnenberg    schedule 05.02.2020
comment
@ PatrikRikama-Hinnenberg developers.google.com/speed/pagespeed/insights/   -  person Eric Lima    schedule 06.02.2020


Ответы (1)


Я много раз изучал это около 4 месяцев назад, и это то, что я обнаружил, но некоторые из приведенных ниже причин были связаны с ошибками в том, как Lighthouse определял скорость страницы на веб-сайтах Gatsby, поэтому некоторые из них могут больше не соответствовать действительности (например, с использованием fadeIn={false} и loading="eager" на изображениях и с использованием тегов a вместо Link из gatsby-link. Оставьте комментарий или отредактируйте, если один из этих советов больше не соответствует действительности.


  • с помощью gatsby-plugin-preact (большое и простое изменение)

  • использование тегов <a> вместо gatsby-link (скорее всего, уже исправлено)

  • с помощью gatsby-plugin-purge-css (удаляет все неиспользуемые CSS. Полезно, если вы используете CSS-фреймворк, например bootstrap)

  • используя fadeIn={false} и loading="eager" в изображениях Gatsby или задав меньшую длительность плавного перехода: durationFadeIn={250}

  • Предварительное подключение к определенным сторонним сайтам с помощью gatsby-plugin-preconnect

  • Если у вас есть фоновое изображение, разделите его на 2 изображения: одно для верхнего сгиба и одно для нижнего сгиба (ваш первоначальный вид страницы должен загружаться меньше в начале).

  • Оптимизация моих изображений над сгибом вручную, прежде чем позволить Гэтсби оптимизировать их. Это был веб-сайт, который я нашел полезным для этого, но вы можете найти для этого хорошее программное обеспечение с открытым исходным кодом. .

  • Загрузка сторонних iframe только после того, как пользователь прокрутил их. Бывший:

       ...
       const ref = useRef()
       const onScreen = useOnScreen(ref, '0px')
       let showWidget
       if (onScreen){
           showWidget = true
       }
       ...
       return (
           <div ref={ref}>
               {showWidget && <ThirdPartyIframe /> }
           </div>
       )
    

Другие советы, о которых я читал, включают


РЕСУРСЫ ДЛЯ ДАЛЬНЕЙШЕЙ ЧТЕНИЯ

Я создал сообщение Reddit, в котором опубликовал нечто подобное, я ' Я рекомендую прочитать комментарии внизу. Он ссылается на эту довольно популярную ветку github, и я обнаружил этот пост, чтобы быть наиболее полезным в теме.

Кроме того, вот несколько вопросов, которые я опубликовал, связанных с увеличением оценки Lighthouse для Gatsby проектов. Вы не должны нуждаться в них с перечисленной выше информацией, но, возможно, они будут полезны или вы чему-то научитесь у них.

person Sam    schedule 24.12.2020