加快盖茨比的表现 [英] Speed Up Gatsby Performance
问题描述
我被赋予一项工作任务,以提高我的项目的性能.目前,Google Lighthouse得分波动不定,但总体上来说得分并不是很高,因此我们正在尝试找出如何提高其性能以向我们的领导者炫耀.
我们的项目将整个Gatsby网站作为单个JavaScript包加载.这将从站点创建一个页面应用程序,该应用程序允许通过JavaScript快速加载新页面.但是,与我们的WordPress网站一样大的东西,会产生很大的兆字节捆绑.如此大的文件包会大大降低页面速度.
我不确定如何解决这个bundle.js的问题,但是我找到了一个有趣的文档,关于这个主题 src/templates/pages.js pageCreators.js createPages.js gatsby-node.js 大约4个月前,我对此进行了调查,这是我发现的,但是下面的某些原因是由于灯塔确定页面速度的错误所致.Gatsby网站,因此有些可能不再适用(例如,在图像上使用 使用 gatsby-plugin-preact (大而轻松更改) 使用 使用 gatsby-plugin-purgecss (删除所有未使用的CSS.如果您使用的是Bootstrap之类的CSS框架,则非常有用 在Gatsby Images上使用 如果您有背景图片,请将其分成两张图片,一张用于折叠上方,另一张用于折叠下方(页面的初始视图在开始时就需要加载较少的图片) 在让盖茨比对其进行优化之前,请手动优化折叠图像.这是一个网站我发现这样做很有帮助,但是您也许可以为此找到一个好的开源软件 仅在用户滚动经过第三方iframe之后才加载它们.例如: 我读过的其他技巧包括 使用内嵌样式(尽管使用301重定向而不是307 (如果适用于您) 进一步阅读的资源 我创建了一个Reddit帖子,在其中发布了类似内容,我建议阅读下面的评论.它引用了这个非常受欢迎的github线程,我发现在灯塔是ap标签.(使用盖茨比)
import从'react'进行React从'prop-types'导入PropTypes从反应头盔"导入头盔从"../layouts/layout"导入布局从'../../util/AnalyticsContext'导入AnalyticsContext,{analyticsEvents}从"../WPComponents/横幅"导入横幅从"../WPComponents/CheckmarkList"导入CheckmarkList从"../WPComponents/CopyGrid"导入CopyGrid从"../WPComponents/Drawers"导入抽屉从"../WPComponents/Explainers"导入解释器从"../WPComponents/Featured"导入精选从"../WPComponents/Form"导入表单从'../WPComponents/Hero'导入Hero从"../WPComponents/Pricing"导入定价从"../WPComponents/PromoApp"导入PromoApp从"../WPComponents/PromoCircles"导入PromoCircles从"../WPComponents/PromoSlider"导入PromoSlider从'../WPComponents/ReachAnimation'导入ReachAnimation从"../WPComponents/Resources"导入资源从'../WPComponents/SimpleExplainer'导入SimpleExplainer从'../WPComponents/SimpleMedia'导入SimpleMedia从"../WPComponents/Solution"导入解决方案从"../WPComponents/感言"导入感言从"../WPComponents/Disclaimer"导入免责声明const PageTemplate = props =>{const {pageContext,data,location} =道具const组件=(pageContext.acf和& pageContext.acf.section_page)||[]让头盔const {yoast} = pageContext如果(最早){const {标题,metadesc,opengraph_title,opengraph_description,opengraph_image,典范,} =酵母头盔=(<头盔标题= {标题||''}meta = {[{名称:"robots",内容:"noindex",},{名称:"description",内容:metadesc ||''},{属性:"og:title",内容:opengraph_title ||''},{属性:'og:site_name',内容:标题||''},{属性:"og:type",内容:网站"},{属性:"og:description",内容:opengraph_description ||''},{属性:"og:image",内容:opengraph_image&&opengraph_image.source_url,},典范?{属性:"og:url",内容:规范||''}:{},]}/>)}返回 (< AnalyticsContext.Provider值= {{... analyticsEvents,}}><布局位置= {位置}>{头盔}{components.map(component => {开关(component .__ typename){案例'WordPressAcf_hero':返回<英雄键= {component.id} {... component}/>案例'WordPressAcf_featured':return< Featured key = {component.id} {... component}/>案例"WordPressAcf_solution":返回<解决方案键= {component.id} {... component}/>案例'WordPressAcf_resources':return< Resources key = {component.id} {... component}/>案例'WordPressAcf_simplemedia':返回< SimpleMedia key = {component.id} {... component}/>案例'WordPressAcf_promoapp':返回< PromoApp键= {component.id} {... component}/>案例"WordPressAcf_reach_animation":返回< ReachAnimation键= {component.id} {... component}/>案例'WordPressAcf_promoslider':返回< PromoSlider键= {component.id} {... component}/>案例'WordPressAcf_promocircles':返回< PromoCircles键= {component.id} {... component}/>案例'WordPressAcf_testimonials':返回<推荐键= {component.id} {... component}/>案例"WordPressAcf_banner":返回<横幅键= {component.id} {... component}/>案例'WordPressAcf_explainers':return< Explainers key = {component.id} {... component}/>案例'WordPressAcf_copygrid':返回< CopyGrid key = {component.id} {... component}/>案例'WordPressAcf_drawers':返回<抽屉键= {component.id} {... component}/>案例'WordPressAcf_simpleexplainer':返回< SimpleExplainer key = {component.id} {... component}/>案例'WordPressAcf_disclaimer':返回<免责声明键= {component.id} {... component}/>案例'WordPressAcf_pricing':返回 (<定价键= {component.id} {... component}/>)案例'WordPressAcf_checkmarklist':返回< CheckmarkList键= {component.id} {... component}/>案例'WordPressAcf_form':返回<表单键= {component.id} {... component}/>默认:console.log('无法识别类型:',component .__ typename)返回}})}</布局></AnalyticsContext.Provider>)}PageTemplate.propTypes = {pageContext:PropTypes.shape({acf:PropTypes.object,媒体:PropTypes.shape({边缘:PropTypes.array,}),}),}导出默认的PageTemplate
const path = require('path')const genericPageTemplate ='src/templates/page.js'const pageCreator = templatePath =>(操作,pageContext)=>{actions.createPage({组件:path.resolve(templatePath),路径:pageContext.pagePath,语境: {... pageContext,},})}module.exports = {createGenericPage:pageCreator(genericPageTemplate),}
const {createGenericPage} = require('./pageCreators')const generatePages = allWordpressPage =>{返回allWordpressPage.edges.map(edge => edge.node)}module.exports =(数据,操作)=>{如果(!data){console.error('createPages()','Error','`data` is undefined')抛出新错误('检索数据时出错:数据未定义')}const {allWordpressPage} =数据const pages = allWordpressPage&&generatePages(allWordpressPage)如果(!页面){console.error('createPages()','错误','无法建立页面.allWordpressPage是虚假的)抛出新的错误(``错误检索数据:allWordpressPage是虚假的'')}页数pages.forEach(page => {//跳过模块"页面如果(page.pagePath ==='/modules/'){返回;}createGenericPage(操作,页面)})}
/***在此文件中实现Gatsby的Node API.**请参阅: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})=>{返回graphql(queryAll).then(res => {如果(错误){res.errors.forEach(错误=> {console.error('错误:',error.message)})}createPages(res.data,操作)}).catch(错误=> {console.error('无法创建页面:',{error})})}Exports.sourceNodes =({action,schema})=>{const {createTypes} =操作const AdditionalTypeDefs = fs.readFileSync(`type-defs.gql`,{编码:`utf-8`,})createTypes(additionalTypeDefs)}//开发环境的临时修复程序:https://github.com/gatsbyjs/gatsby/issues/11934#issuecomment-469046186exports.onCreateWebpackConfig =({getConfig,stage})=>{const config = getConfig()如果(stage.startsWith('develop')&& config.resolve){config.resolve.alias = {... config.resolve.alias,'react-dom':'@ hot-loader/react-dom',}}}
fadeIn = {false}
和 loading ="eager"
,并使用 a
标记而不是 gatsby-link
中的 Link
.如果这些技巧之一不再成立,请发表评论或进行编辑.< a>
标记而不是 gatsby-link
fadeIn = {false}
和 loading ="eager"
或将渐隐的持续时间设置为较短: durationFadeIn = {250}
...const ref = useRef()const onScreen = useOnScreen(ref,'0px')让showWidget如果(在屏幕上){showWidget = true}...返回 (< div ref = {ref}>{showWidget&&< ThirdPartyIframe/>}</div>)
While I don't completely understand these docs yet I believe that I edit this async-requires.js file to include multiple export component lines and this should result in multiple javascript bundles instead of the main large one. Perhaps if there are multiple js bundles the site will load faster because it is not just bottle necked by one. So a page can load in the specific bundle it needs to render and async load the one it doesn't need.
Below is some of the code that I think relates to the task at hand. I'm still a bit of a beginner when it comes to gatsby so I'm not exactly sure what I can change here to allow for better performance.
Thank you for the help.
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/templates/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',
}
}
}
I looked into this a lot about 4 months ago and this is what I found, but some of the reasons below were due to bugs in how lighthouse determined pagespeed on Gatsby websites, so a few may not true anymore (for example, using fadeIn={false}
and loading="eager"
on images, and using a
tags instead of Link
from gatsby-link
. Please leave a comment or edit if one of these tips is no longer true.
using gatsby-plugin-preact (big and easy change)
using
<a>
tags instead ofgatsby-link
using gatsby-plugin-purge-css (removes all you unused CSS. Useful if you're using a CSS framework like bootstrap)
using
fadeIn={false}
andloading="eager"
on Gatsby Images, or setting the duration of the fade in to be lower:durationFadeIn={250}
Preconnecting to certain 3rd party sites with gatsby-plugin-preconnect
If you have a background image, split it into 2 images, one for above the fold and one for below the fold (your initial view of the page has to load less at the beginning)
Optimizing my above the fold images manually before letting gatsby optimize them. This was a website I found helpful for doing that, but you may be able to find a good open source software for that.
Loading third party iframes after only after the user scrolls past them. Ex:
... const ref = useRef() const onScreen = useOnScreen(ref, '0px') let showWidget if (onScreen){ showWidget = true } ... return ( <div ref={ref}> {showWidget && <ThirdPartyIframe /> } </div> )
Other tips I've read about include
Using inline styling (although I've heard Gatsby does this automatically)
Using a 301 redirect instead of 307 (If this applies to you)
Not using Typography.js
Possibly using an S3 & Cloudfront and not Netlify to host the website
RESOURCES TO READ FURTHER
I created a reddit post where I posted something similar, I'd recommend reading the comments underneath. It references this github thread which is pretty popular, and I found this post to be the most helpful on the thread.
As well, here's a number of questions I posted related to increasing the lighthouse score for Gatsby
projects. You shouldn't need them with the information listed above, but maybe they'll be useful or you'll learn something from them
- Largest contententful paint (LCP) on lighthouse is a p tag. (Using gatsby)
- Pagespeed insights avoid chaining critical request only lists Initial navigation followed by my domain twice
- Reduce initial server response time with Netlify and Gatsby
- Largest contentful paint is one big gatsby-background-image and very slow, PageSpeed Insights tells me to preconnect third-party origins and then tells me they are not used by the browser after preconnecting
- PageSpeed Insights diagnostic "Ensure text remains visible during webfont load"
- Load third party iframe in React after page load, so that the iframe does not affect PageSpeed score
这篇关于加快盖茨比的表现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!