加快 Gatsby 性能
Posted
技术标签:
【中文标题】加快 Gatsby 性能【英文标题】:Speed Up Gatsby Performance 【发布时间】:2020-05-20 17:46:51 【问题描述】:我在工作中被分配了一项任务,以提高我的项目的性能。目前,Google Lighthouse 的分数在波动,但总体而言分数并不高,因此我们正在努力弄清楚如何提高其性能,以便能够向我们的领导者炫耀。
我们的项目将整个 Gatsby 网站加载为单个 javascript 包。这会从站点创建一个单页应用程序,它允许通过 JavaScript 快速加载新页面。但是对于像我们的 WordPress 网站这样大的东西,这会产生以兆字节为单位的非常大的捆绑包。这个大包显着降低了页面速度。
我不完全确定如何卸载这个 bundle.js,但我发现了一个关于该主题的有趣文档 https://www.gatsbyjs.org/docs/how-code-splitting-works/
虽然我还没有完全理解这些文档,但我相信我编辑了这个 async-requires.js 文件以包含多个导出组件行,这应该会导致多个 javascript 包而不是主要的大型包。也许如果有多个 js 包,网站加载速度会更快,因为它不仅仅是一个瓶颈。因此,页面可以加载到它需要渲染的特定包中,并异步加载它不需要的包。
以下是我认为与手头任务相关的一些代码。在 gatsby 方面,我还是个初学者,所以我不确定我可以在此处进行哪些更改以提高性能。
感谢您的帮助。
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',
【问题讨论】:
您介意分享一下developers.google.com/speed/pagespeed/insights 对网站的评价吗? @PatrikRikama-Hinnenberg developers.google.com/speed/pagespeed/insights/… 【参考方案1】:大约 4 个月前,我对此进行了很多研究,这就是我发现的,但下面的一些原因是由于 lighthouse 如何确定 Gatsby 网站上的页面速度存在错误,所以有些可能不再正确(例如,在图像上使用fadeIn=false
和loading="eager"
,并使用a
标签而不是gatsby-link
中的Link
。如果这些提示之一不再适用,请发表评论或编辑。
使用gatsby-plugin-preact(大而简单的更改)
使用<a>
标签而不是gatsby-link
(现在很可能已修复)
使用gatsby-plugin-purge-css(删除所有未使用的 CSS。如果您使用的是引导程序等 CSS 框架,则很有用)
在 Gatsby 图像上使用 fadeIn=false
和 loading="eager"
,或者将淡入的持续时间设置为更低:durationFadeIn=250
使用gatsby-plugin-preconnect预连接到某些第 3 方网站
如果您有背景图片,请将其拆分为 2 张图片,一张用于首屏,一张用于首屏(您的页面初始视图必须在开始时加载较少)
在让 gatsby 优化它们之前手动优化我的“首屏”图像。 This was a website 我发现这样做很有帮助,但你也许可以找到一个好的开源软件。
仅在用户滚动经过第三方 iframe 后才加载它们。例如:
...
const ref = useRef()
const onScreen = useOnScreen(ref, '0px')
let showWidget
if (onScreen)
showWidget = true
...
return (
<div ref=ref>
showWidget && <ThirdPartyIframe />
</div>
)
我读过的其他提示包括
Using inline styling(虽然I've heard Gatsby does this automatically)
Using a 301 redirect instead of 307(如果这适用于您)
不使用Typography.js
Possibly using an S3 & Cloudfront and not Netlify to host the website
进一步阅读的资源
I created a reddit post 我在其中发布了类似的内容,我建议阅读下面的 cmets。 It references this github thread which is pretty popular,我发现 this post 是该主题中最有帮助的。
此外,我还发布了一些与提高 Gatsby
项目的灯塔分数相关的问题。上面列出的信息你不应该需要它们,但也许它们会很有用,或者你会从它们身上学到一些东西
【讨论】:
以上是关于加快 Gatsby 性能的主要内容,如果未能解决你的问题,请参考以下文章
Gatsby:graphql 查询中的 gatsby-source-graphql 和 gatsby-plugin-sharp
MDX 中的 Gatsby 静态图像(gatsby-plugin-image)
gatsby-image-plugin,StaticImage 不能覆盖默认的包装样式(gatsby-image-wrapper & gatsby-image-wrapper-constrai
Gatsby - webpack 无法使用 `gatsby-plugin-alias-imports` 解析别名导入