我在工作中接到了一项提高项目绩效的任务。目前,Google Lighthouse 的得分会有所波动,但总体而言得分并不高,因此我们正在努力弄清楚如何提高其性能,以便向我们的领导层炫耀。
我们的项目将整个 Gatsby 站点作为单个 JavaScript 包加载。这会从站点创建一个单页应用程序,允许通过 JavaScript 快速加载新页面。但是对于像我们的 WordPress 网站一样大的东西,这会产生一个非常大的包,以兆字节为单位。这个大包显着降低了页面速度。
我不太确定如何卸载这个 bundle.js,但我发现了一个关于这个主题的有趣文档https://www.gatsbyjs.org/docs/how-code-splitting-works/
虽然我并不完全理解这些文档,但我相信我编辑了这个 async-requires.js 文件以包含多个导出组件行,这应该会导致多个 javascript 包而不是主要的大包。也许如果有多个 js 包,站点会加载得更快,因为它不仅仅是一个瓶颈。因此,页面可以加载到它需要呈现的特定包中,并异步加载它不需要的包。
下面是一些我认为与手头任务相关的代码。当谈到 gatsby 时,我仍然是一个初学者,所以我不确定我可以在这里改变什么来获得更好的性能。
感谢您的帮助。
异步-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" */)
}
源代码/模板/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),
}
创建页面.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',
}
}
}