На работе мне дали задание повысить производительность моего проекта. В настоящее время оценка 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',
}
}
}