Jones Smith
Jones Smith

Reputation: 380

Netlify throwing errors on my Gatsby JS about jQuery

Trying to deploy my Gatsby app on netlify. Basically, I added some jQuery for some specific purposes but when I uploaded it, I got the ff error:

11:52:55 AM: failed Building static HTML for pages - 5.342s
11:52:55 AM: error Building static HTML failed
11:52:55 AM: 
11:52:55 AM:   4 |   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
11:52:55 AM:   5 |   */
11:52:55 AM: > 6 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?

[jQuery snippet here]

11:52:56 AM: npm ERR! errno 1
11:52:56 AM: npm ERR! [email protected] build: `gatsby build`
11:52:56 AM: npm ERR! Exit status 1
11:52:56 AM: npm ERR!
11:52:56 AM: npm ERR! Failed at the [email protected] build script.
11:52:56 AM: npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
11:52:56 AM: npm ERR! A complete log of this run can be found in:
11:52:56 AM: npm ERR!     /opt/buildhome/.npm/_logs/2021-01-19T03_52_56_065Z-debug.log

In between of these errors its showing this:

enter image description here

There is only one place where i've added jQuery, its on my Layout component:

import React from "react"
import "bootstrap/dist/css/bootstrap.min.css"
import "jquery/dist/jquery.min.js"
import "popper.js/dist/popper.min"
import "bootstrap/dist/js/bootstrap.min.js"
import "../assets/css/owl.carousel.min.css"
import "../assets/css/style.css"
import 'aos/dist/aos.css'

import Helmet from "react-helmet"
import AOS from 'aos'
import { withPrefix } from "gatsby"
import Navbar from '../components/Navbar'
import Footer from '../components/Footer'

AOS.init();

const Layout = ({ children }) => {
  return (
     <>
      <Helmet>
          <script src={withPrefix('owl.carousel.min.js')} type="text/javascript" />
          <script src={withPrefix('sticky-menu.js')} type="text/javascript" />
          <script src={withPrefix('script.js')} type="text/javascript" />
      </Helmet>
     <Navbar />
     { children }
     <Footer />
     </>
  )
  
}


export default Layout

You can actually see this on my package.json that it was added:

"dependencies": {
    "@popperjs/core": "^2.5.3",
    "aos": "^3.0.0-beta.6",
    "bootstrap": "^4.5.3",
    "gatsby": "^2.24.76",
    "gatsby-image": "^2.4.21",
    "gatsby-plugin-prefetch-google-fonts": "^1.4.3",
    "gatsby-source-strapi": "0.0.12",
    "gatsby-transformer-sharp": "^2.5.17",
    "jquery": "^3.5.1",
    "jquery-nav-scroll": "^1.4.1",
    "popper.js": "^1.16.1",
    "react": "^16.12.0",
    "react-anchor-link-smooth-scroll": "^1.0.12",
    "react-dom": "^16.12.0",
    "react-helmet": "^6.1.0",
    "react-icons": "^3.11.0",
    "react-markdown": "^4.3.1",
    "react-scrollspy": "^3.4.3"
  },

Not sure how to fix this, been over here for the last couple of hours. Any idea how do I fix this thing?

Upvotes: 1

Views: 634

Answers (1)

Ferran Buireu
Ferran Buireu

Reputation: 29320

As I was saying, it's not Netlify's fault since the project is not building locally. You should ensure always that your project is correctly coded in both environments (build and develop) since they have substantial differences between them. A project that works under gatsby develop doesn't mean that it's perfectly coded, only means that it work under certain conditions. You can check the overview between runtime and build-time in Gatsby's docs, the main difference relies on gatsby build's Gatsby Server-Side Rendering (SSR). Keep in mind that you are using jQuery, which points directly to the real DOM, having a high-performance impact on the site, while React, creates and manipulates a virtual DOM (vDOM) to avoid that kind of high-cost actions. It's odd using both approaches.

In addition, you are importing everything in the <Layout> component, which will be used across your project in multiple components/pages. This may lead to multiple script rendering/loading if the component is rerendered.

Said that, your issue may be caused by:

  • AOS.init();
  • The script importation: since they aren't promises, they will be imported at the same time. If for some reason one of them is loaded first (the lighter) and it's dependant on the other one, it will break your project, since it won't be able to load. You are not loading jQuery, unless it's in scripts.js.

You have many approaches, from changing the approach and using a React-based one, to try to async the script importation (and loading jQuery before), but all the workarounds will need to be tested with some trials and errors:

Loading jQuery before:

  <Helmet>
      <script
    src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
    crossorigin="anonymous"/>
      <script async src={withPrefix('owl.carousel.min.js')} type="text/javascript" />
      <script async src={withPrefix('sticky-menu.js')} type="text/javascript" />
      <script async src={withPrefix('script.js')} type="text/javascript" />
  </Helmet>

Use the async property to try to wait for the other scripts. Alternatively, you can download jQuery and add it statically as you do with the rest of the dependencies.

Using an async/await based approach:

  import * as loadScript from 'simple-load-script';
  import 'babel-polyfill'; // must be imported for async/await to work, see e.g. https://github.com/gatsbyjs/gatsby/pull/3369#issuecomment-354599985


    const Layout = ({ children }) => {

     useEffect(()=>{
        await loadScript('https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js', { inBody: true });
        await loadScript('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js', { inBody: true });
     }, [])   

      return (
         <>
         <Navbar />
         { children }
         <Footer />
         </>
      )
      
    }

Note: from https://github.com/gatsbyjs/gatsby/issues/3182

With this approach, you are waiting for the script loading in the useEffect hook with loadScript (from simple-load-script) library, used with empty deps ([]) is like using it as a componentDidMount lifecycle, or in other words, once the DOM tree is loaded (asynchronously).

Using the SSR:

In your gatsby-ssr.js:

import React from 'react';

export const onRenderBody = ({ setHeadComponents }, pluginOptions) => {
  setHeadComponents([
    <script
      src="https://code.jquery.com/jquery-3.4.1.min.js"
      integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
      crossOrigin="anonymous">
    </script>,
  ])
}

The, in your gatsby-browser.js:

const $ = require("jquery")

export const onInitialClientRender = () => {
  $(document).ready(function () {
    console.log("The answer is don't think about it!")
  });
}

This will load jQuery on the SSR using onRenderBody API across with onInitialClientRender (the first rendering of the client) avoiding subsequently renderings as your approach may lead.

Upvotes: 1

Related Questions