gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.29k stars 10.31k forks source link

Decreasing the size of component--src-pages--index.js generated by Gatsby. #23517

Closed Karansidds closed 4 years ago

Karansidds commented 4 years ago

23047 Summary

So, I've created an e-commerce website using Gatsby and I've loved everything about Gatsby such as prefetching, performance, etc. But, when I test my site using Google Lighthouse, I get a very less score for performance. Taking a look at the issues of my website, time to first byte(TTFB) is more than 5 seconds. So, I compared my site to Gatsby's site and I saw a big difference in the size of the component--src-pages generated by Gatsby. The size of every page of Gatsby's blog was less than 100KB, but for my website it was more than 1MB for every page. Thus, the size of my website had exceeded 8MB. Due to this, mobiles with slow network and processing were unable to load my website in a matter of seconds as they had to download resources worth 8MB. Sometimes, it took minutes to load the website. And also, everytime I click on a link to another page it took 2 seconds to respond and then load the page. This is a serious issue to me as this is not a personal project and is used by a startup with more than 2k customers. How can I decrease the size of my website and also improve TTFB and other performance issues?

Relevant information

My Site

InkedCapture_LI

Gatsby Blog

Capture

Lighthouse Audit

Lighthouse

Index.js

import { navigate } from "@reach/router"
import { MDBContainer } from "mdbreact"
import useWindowSize from "react-use/lib/useWindowSize"
import Confetti from "react-confetti"
import Layout from "../components/Layout"
import NavBar from "../components/Navbar/Navbar"
import Header from "../components/Header/Header"
import Features from "../components/Features/Features"
import CategoryCards from "../components/Categories/Categories"
import BrandCategories from "../components/BrandCards/BrandCards"
import { ProductItems } from "../components/Products/Products"
import StickyFooter from "../components/StickyFooter/StickyFooter"
import Footer from "../components/Footer/Footer"
import SEO from "../components/Seo"
import Loader from "../components/Loader/Loader"
import Steps from "../components/Steps/Steps"
import useFirebase from "../scripts/useFirebase"

const IndexPage = props => {
  const firebase = useFirebase()

  let [loading, updateLoading] = useState(true)

  let [user, updateUser] = useState(undefined)

  let [checkout, updateCheckout] = useState(false)

  const { width, height } = useWindowSize()

  useEffect(() => {
    if (!firebase) return

    if (typeof window == "undefined") return

    let mounted = true

    if (props.location.state !== null) {
      if (mounted) updateCheckout(props.location.state.checkout)
    }

    const onLogin = async () => {
      await firebase.auth().onAuthStateChanged(function(user) {
        if (user) {
          if (mounted) updateUser(user.displayName)
        } else {
          navigate("/login/")
        }
      })
    }

    onLogin()

    //Loading Timer
    if (mounted) updateLoading(false)

    return () => (mounted = false)
  }, [firebase, user])

  const onCheckout = () => {
    const swal = require("@sweetalert/with-react")
    if (checkout) {
      swal(
        "SHAGUN",
        "You Saved Rs." + props.location.state.savings + ". Congratulations!"
      ).then(() => {
        updateCheckout(!checkout)
      })
    }
  }

  onCheckout()

  return (
    <Layout>
      {user === "" ? (
        navigate("/login/")
      ) : loading ? (
        <React.Fragment>
          <NavBar />
          <StickyFooter />
          <Loader loading={loading} />
        </React.Fragment>
      ) : (
        <React.Fragment>
          <SEO
            title="Home"
            description="Shagun is a Belgaum based ecommerce business which aims at delivering the day to day items at the lowest price ever."
            lang="en"
          />
          {checkout && <Confetti width={width} height={height} />}
          <NavBar navbar={"Working"} search={"search"} />
          <Header />
          <ProductItems />
          <CategoryCards />
          <BrandCategories />
          <Features />
          <Steps />
          <StickyFooter />
          <Footer updateUser={updateUser} />
        </React.Fragment>
      )}
    </Layout>
  )
}

export default IndexPage

Environment (if relevant)

 System:
    OS: Windows 10 10.0.18363
    CPU: (8) x64 AMD Ryzen 5 2400G with Radeon Vega Graphics    
  Binaries:
    Node: 12.12.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.19.1 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
    npm: 6.14.4 - C:\Users\karan\AppData\Roaming\npm\npm.CMD
  Languages:
    Python: 3.6.4
  Browsers:
    Edge: 44.18362.449.0
  npmPackages:
    gatsby: ^2.20.27 => 2.20.27 
    gatsby-cli: ^2.11.13 => 2.11.13 
    gatsby-image: ^2.2.38 => 2.3.4 
    gatsby-image-background-slider: 0.0.1 => 0.0.1 
    gatsby-plugin-emotion: ^4.1.21 => 4.2.2 
    gatsby-plugin-google-analytics: ^2.1.35 => 2.2.4 
    gatsby-plugin-guess-js: ^1.2.4 => 1.2.4 
    gatsby-plugin-loadable-components-ssr: ^2.0.0 => 2.0.0 
    gatsby-plugin-manifest: ^2.3.3 => 2.3.5 
    gatsby-plugin-netlify: ^2.2.3 => 2.2.3 
    gatsby-plugin-netlify-cache: ^1.2.0 => 1.2.0 
    gatsby-plugin-nprogress: ^2.2.3 => 2.2.3 
    gatsby-plugin-offline: ^3.1.4 => 3.1.4 
    gatsby-plugin-preact: ^3.2.3 => 3.2.3 
    gatsby-plugin-prefetch-google-fonts: ^1.4.3 => 1.4.3 
    gatsby-plugin-purgecss: ^5.0.0 => 5.0.0 
    gatsby-plugin-purify-css: ^2.2.1 => 2.2.1 
    gatsby-plugin-react-helmet: ^3.1.18 => 3.2.4 
    gatsby-plugin-robots-txt: ^1.5.0 => 1.5.0 
    gatsby-plugin-sass: ^2.2.3 => 2.2.3 
    gatsby-plugin-sharp: ^2.5.6 => 2.5.6 
    gatsby-plugin-sitemap: ^2.2.27 => 2.3.5 
    gatsby-plugin-typography: ^2.3.20 => 2.4.3 
    gatsby-plugin-webpack-bundle-analyser-v2: ^1.1.8 => 1.1.8 
    gatsby-source-filesystem: ^2.2.4 => 2.2.4 
    gatsby-transformer-json: ^2.3.3 => 2.3.3 
    gatsby-transformer-sharp: ^2.4.6 => 2.4.6 

### File contents (if changed)

`gatsby-config.js`: 
```module.exports = {
  siteMetadata: {
    title: `Shagun Delivery Services`,
    description: `Shagun is a student based entrepreneur company aiming to deliver day to day products to your doorstep.`,
    author: `Karan Siddannavar`,
    siteUrl: `https://www.shagundelivery.com`,
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    `gatsby-transformer-json`,

    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/images`,
        name: `images`,
      },
    },
    {
      resolve: "gatsby-plugin-robots-txt",
      options: {
        host: "https://www.shagundelivery.com",
        sitemap: "https://www.shagundelivery.com/sitemap.xml",
        policy: [
          {
            userAgent: "*",
            allow: "/",
          },
        ],
      },
    },
    {
      resolve: `gatsby-plugin-google-analytics`,
      options: {
        // The property ID; the tracking code won't be generated without it
        trackingId: process.env.GOOGLE_ANALYTICS_TRACKING_ID || "none",
        head: true,
      },
    },
    `gatsby-plugin-sitemap`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-prefetch-google-fonts`,
      options: {
        fonts: [
          {
            family: `Poppins`,
            variants: [`100`, `200`, `300`, `500`],
          },
          {
            family: `Open Sans`,
            variants: [`100`, `200`, `400`, `500`],
          },
          {
            family: `PT Sans`,
            variants: [`100`, `200`, `400`, `500`],
          },
        ],
      },
    },
    `gatsby-plugin-sass`,
    {
      resolve: `gatsby-plugin-nprogress`,
      options: {
        // Setting a color is optional.
        color: `#f3752b`,
        // Disable the loading spinner.
        showSpinner: false,
        minimum: 0.4,
      },
    },
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: "SHAGUN",
        short_name: "Shagun Delivery",
        start_url: "/",
        background_color: "#FFFF00",
        theme_color: "#000000",
        // Enables "Add to Homescreen" prompt and disables browser UI (including back button)
        // see https://developers.google.com/web/fundamentals/web-app-manifest/#display
        display: "standalone",
        icon: "src/images/icon.png", // This path is relative to the root of the site.
        // An optional attribute which provides support for CORS check.
        // If you do not provide a crossOrigin option, it will skip CORS for manifest.
        // Any invalid keyword or empty string defaults to `anonymous`
        crossOrigin: `use-credentials`,
      },
    },
    `gatsby-plugin-netlify`,
    `gatsby-plugin-netlify-cache`,
    {
      resolve: "gatsby-plugin-webpack-bundle-analyser-v2",
      options: {
        devMode: true,
      },
    },
    {
      resolve: `gatsby-plugin-offline`,
      options: {
        appendScript: require.resolve(`./sw.js`),
      },
    },
  ],
}

package.json:

{
  "name": "Shagun",
  "private": true,
  "description": "An ecommerce company aiming to delivery day to day requirements",
  "version": "0.1.0",
  "author": "Karan Siddannavar <karansiddannavar09@gmail.com>",
  "dependencies": {
    "@emotion/core": "^10.0.27",
    "@fortawesome/fontawesome-svg-core": "^1.2.26",
    "@fortawesome/free-solid-svg-icons": "^5.12.0",
    "@fortawesome/react-fontawesome": "^0.1.8",
    "@reach/router": "^1.3.3",
    "@sweetalert/with-react": "^0.1.1",
    "animate.css": "^3.7.2",
    "axios": "^0.19.2",
    "bootstrap": "^4.4.1",
    "cloudinary-react": "^1.4.0",
    "css-ripple-effect": "^1.0.5",
    "eslint-plugin-react-hooks": "^2.3.0",
    "firebase": "^7.14.1",
    "firebaseui": "^4.4.0",
    "fuse.js": "^3.4.6",
    "gatsby-image": "^2.2.38",
    "gatsby-image-background-slider": "0.0.1",
    "gatsby-plugin-emotion": "^4.1.21",
    "gatsby-plugin-google-analytics": "^2.1.35",
    "gatsby-plugin-guess-js": "^1.2.4",
    "gatsby-plugin-loadable-components-ssr": "^2.0.0",
    "gatsby-plugin-manifest": "^2.3.3",
    "gatsby-plugin-netlify": "^2.2.3",
    "gatsby-plugin-netlify-cache": "^1.2.0",
    "gatsby-plugin-nprogress": "^2.2.3",
    "gatsby-plugin-offline": "^3.1.4",
    "gatsby-plugin-preact": "^3.2.3",
    "gatsby-plugin-prefetch-google-fonts": "^1.4.3",
    "gatsby-plugin-purgecss": "^5.0.0",
    "gatsby-plugin-purify-css": "^2.2.1",
    "gatsby-plugin-react-helmet": "^3.1.18",
    "gatsby-plugin-robots-txt": "^1.5.0",
    "gatsby-plugin-sass": "^2.2.3",
    "gatsby-plugin-sharp": "^2.5.6",
    "gatsby-plugin-sitemap": "^2.2.27",
    "gatsby-plugin-typography": "^2.3.20",
    "gatsby-source-filesystem": "^2.2.4",
    "gatsby-transformer-json": "^2.3.3",
    "gatsby-transformer-sharp": "^2.4.6",
    "imagekit-react": "^0.1.0",
    "imagekitio-react": "^1.0.5",
    "jquery": "^3.5.0",
    "loaders.css": "^0.1.2",
    "lodash.isequal": "^4.5.0",
    "lozad": "^1.14.0",
    "mdbreact": "^4.25.6",
    "moment": "^2.24.0",
    "node-sass": "^4.13.1",
    "popper.js": "^1.16.0",
    "preact": "^10.4.1",
    "prop-types": "^15.7.2",
    "razorpay": "^2.0.6",
    "react": "^16.13.1",
    "react-anchor-link-smooth-scroll": "^1.0.12",
    "react-autosuggest": "^10.0.0",
    "react-bootstrap": "^1.0.0-beta.16",
    "react-collapsible": "^2.6.2",
    "react-compound-timer": "^1.1.15",
    "react-confetti": "^5.0.1",
    "react-datepicker": "^2.12.1",
    "react-dom": "^16.13.1",
    "react-dropdown": "^1.6.4",
    "react-emotion": "^10.0.0",
    "react-helmet": "^6.0.0",
    "react-hooks": "^1.0.1",
    "react-id-generator": "^3.0.0",
    "react-lazy-load": "^3.0.13",
    "react-loaders": "^3.0.1",
    "react-loading-skeleton": "^2.0.1",
    "react-reveal": "^1.2.2",
    "react-router-dom": "^5.1.2",
    "react-select": "^3.0.8",
    "react-slick": "^0.25.2",
    "react-slidedown": "^2.4.5",
    "react-social-icons": "^4.1.0",
    "react-spinners": "^0.8.0",
    "react-spring": "^8.0.27",
    "react-sweet-progress": "^1.1.2",
    "react-use": "^13.27.0",
    "sal.js": "^0.7.1",
    "slick-carousel": "^1.8.1",
    "sweetalert": "^2.1.2",
    "sweetalert2": "^9.10.12",
    "sweetalert2-react-content": "^3.0.0",
    "transform-loader": "^0.2.4",
    "util": "^0.12.2"
  },
  "devDependencies": {
    "gatsby": "^2.20.27",
    "gatsby-cli": "^2.11.13",
    "gatsby-plugin-webpack-bundle-analyser-v2": "^1.1.8",
    "prettier": "^1.19.1"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "format": "prettier --write \"**/*.{js,jsx,json,md}\"",
    "start": "npm run develop",
    "serve": "gatsby serve",
    "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/gatsbyjs/gatsby-starter-default"
  },
  "bugs": {
    "url": "https://github.com/gatsbyjs/gatsby/issues"
  }
} 

gatsby-node.js:

const path = require("path")
// const products = require("./src/components/Products/products.json")

exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
  if (stage === "build-html") {
    actions.setWebpackConfig({
      externals: getConfig().externals.concat(function(
        context,
        request,
        callback
      ) {
        const regex = /^@?firebase(\/(.+))?/
        // exclude firebase products from being bundled, so they will be loaded using require() at runtime.
        if (regex.test(request)) {
          return callback(null, "umd " + request)
        }
        callback()
      }),
    })
  }
}

exports.createPages = async ({ page, actions }) => {
  const { createPage } = actions

  const categoryPage = path.resolve("./src/templates/categories.js")
  const brandPage = path.resolve("./src/templates/brands.js")

  const axios = require("axios")

  const categories = [
    "Groceries",
    "Milk Products",
    "Snacks And Chocolates",
    "Edible Oil",
    "Beverages",
    "Health Care",
    "Readymix N Sauces",
    // "Detergents",
    // "Soaps",
    // "Masala",
    // "Household Items",
    // "Stationary",
    // "Soaps",
    // "Cleaning Agents",
    // "Dish Washers",
    // "Hair Care",
    // "Personal Care",
  ]

  categories.forEach(category => {
    createPage({
      path: `/products/category/${category}/`,
      component: categoryPage,
      context: { category },
    })
  })

  let brands = ["Amul", "Britannia", "Cadbury", "Dabur"]

  brands.forEach(brand => {
    createPage({
      path: `/products/brand/${brand}/`,
      component: brandPage,
      context: { brand },
    })
  })
}

exports.onCreatePage = async ({ page, actions }) => {
  const { createPage } = actions

  const productPage = path.resolve("./src/templates/product.js")

  if (page.path.match(/^\/products/)) {
    createPage({
      path: "/products/product/",
      matchPath: "/products/product/*",
      component: productPage,
    })
  }
} 

gatsby-browser.js:

import "bootstrap/js/dist/dropdown"
import "bootstrap/dist/css/bootstrap.min.css"
import "mdbreact/dist/css/mdb.css"
import "@fortawesome/fontawesome-free/css/all.min.css"
import "slick-carousel/slick/slick.css"
import "slick-carousel/slick/slick-theme.css"
import "react-slidedown/lib/slidedown.css"
import "css-ripple-effect/dist/ripple.min.css"

export const onServiceWorkerUpdateReady = () => {
  window.location.href = "/"
  window.location.reload()
}

export const registerServiceWorker = () => true 

gatsby-ssr.js: N/A

thundermiracle commented 4 years ago

It's properly a fontawesome icons tree-shaking problem. Add babel-plugin-transform-imports plugin and try tree-shaking @fortawesome/free-solid-svg-icons" . See the example here.

Karansidds commented 4 years ago

It's properly a fontawesome icons tree-shaking problem. Add babel-plugin-transform-imports plugin and try tree-shaking @fortawesome/free-solid-svg-icons" . See the example here.

I am not using @fortawesome/free-solid-svg-icons, I've just installed it. But, I'm not using it anywhere. I've to remove it.

thundermiracle commented 4 years ago

I am not using @fortawesome/free-solid-svg-icons Then try using webpack-bundle-analyzer to find out the problem.

LekoArts commented 4 years ago

Thank you for opening this!

You're importing quite some stuff in your files. Material Design, FontAwesome icons, Bootstrap (already the CSS in your gatsby-browser.js is probably really heavy), Firebase.

I'd suggest cutting down on your CSS, throw out unused/unnecessary packages and anaylze your bundles with: https://github.com/JimmyBeldone/gatsby-plugin-webpack-bundle-analyser-v2

You're also having multiple styling libraries in your package.json (e.g. emotion, css) or heavy packages like lodash. Make sure to be cautious about them.

We're marking this issue as answered and closing it for now but please feel free to comment here if you would like to continue this discussion. We also recommend heading over to our communities if you have questions that are not bug reports or feature requests. We hope we managed to help and thank you for using Gatsby!

Karansidds commented 4 years ago

Thank you for opening this!

You're importing quite some stuff in your files. Material Design, FontAwesome icons, Bootstrap (already the CSS in your gatsby-browser.js is probably really heavy), Firebase.

I'd suggest cutting down on your CSS, throw out unused/unnecessary packages and anaylze your bundles with: https://github.com/JimmyBeldone/gatsby-plugin-webpack-bundle-analyser-v2

You're also having multiple styling libraries in your package.json (e.g. emotion, css) or heavy packages like lodash. Make sure to be cautious about them.

We're marking this issue as answered and closing it for now but please feel free to comment here if you would like to continue this discussion. We also recommend heading over to our communities if you have questions that are not bug reports or feature requests. We hope we managed to help and thank you for using Gatsby!

Yeah! I agree that there lots of external css libraries that are being installed. But, how would it affect the bundle if it's not being used in the project? And my main question is not being answered, how can I reduce the size of component--src-pages that is generated by Gatsby for every page in the src/pages directory? For some pages where there's just text and no other heavy libraries even those pages are more than 1MB. I've mentioned that in the beginning of the question with some images. Please take a look at it as it's important.

LekoArts commented 4 years ago

You're importing this into every page:

import "bootstrap/js/dist/dropdown"
import "bootstrap/dist/css/bootstrap.min.css"
import "mdbreact/dist/css/mdb.css"
import "@fortawesome/fontawesome-free/css/all.min.css"
import "slick-carousel/slick/slick.css"
import "slick-carousel/slick/slick-theme.css"
import "react-slidedown/lib/slidedown.css"
import "css-ripple-effect/dist/ripple.min.css"

You can use the bundle analyzer to see why the pages chunks are so heavy, for me this would be a guessing game :)

Karansidds commented 4 years ago

You're importing this into every page:

import "bootstrap/js/dist/dropdown"
import "bootstrap/dist/css/bootstrap.min.css"
import "mdbreact/dist/css/mdb.css"
import "@fortawesome/fontawesome-free/css/all.min.css"
import "slick-carousel/slick/slick.css"
import "slick-carousel/slick/slick-theme.css"
import "react-slidedown/lib/slidedown.css"
import "css-ripple-effect/dist/ripple.min.css"

You can use the bundle analyzer to see why the pages chunks are so heavy, for me this would be a guessing game :)

I think this could help me. Can you just tell me how could I use babel-plugin-transform-imports in my website considering you've taken a look at the libraries that I'm using? This would help me a lot.

Karansidds commented 4 years ago

I would like to open this issue as the problem is not solved. I removed all of the css files from the gatsby-browser.js files and the size still remains the same. Please open this issue!

LekoArts commented 4 years ago

I closed the issue as it's not a problem with Gatsby but your individual project. Using the bundle-analyzer should give you the correct information why your bundle is so big.

thundermiracle commented 4 years ago

LekoArts is right. You'll face same problem no matter you're using next.js, create-react-app, webpack only or Gatsby. You have to learn how to use bundle-analyzer for all of your projects.

Karansidds commented 4 years ago

I checked the bundle analyzer as well. There every page is less than 100 kb. But, in production mode the component-pages-index.js goes above 1MB. What can I do in such case?

MANTENN commented 4 years ago

LekoArts is right. You'll face same problem no matter you're using next.js, create-react-app, webpack only or Gatsby. You have to learn how to use bundle-analyzer for all of your projects.

How can I move out hard coded information into page-data.json or chunk into separate files page-data-state? this is because index bundle contains html which increases file size, parsing time, compilatio and executation for pages with the same dataset...logos, svgs, images, etc.