Gatsby: [v2] Cannot build for production when using Redux

Created on 10 Jul 2018  ยท  16Comments  ยท  Source: gatsbyjs/gatsby

Description

When I'm trying to build for production an error occurs:
WebpackError: Invariant Violation: Could not find "store" in either the context or props of "Connect(FiltersPage)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(FiltersPage)".

Steps to reproduce

Component with connected Redux:
```import React, { Component } from 'react'
import { connect } from 'react-redux'
import { graphql } from 'gatsby'

import Layout from '../components/Layouts/filters'
import { arrayCombineUnique, extractNode, parseQueryFilters } from '../utils/helpers'
import { filtersActions } from '../components/Filters/state'
import ItemGroups from '../components/Items/ItemGroups'

class FiltersPage extends Component {
componentDidMount () {
const { setFilters, pageContext, data } = this.props

const hotelsCategories = extractNode(data.allFirestoreHotel, 'categories')
const allHotelsUniqueCategories = arrayCombineUnique(hotelsCategories)

const toursCategories = extractNode(data.allFirestoreTour, 'categories')
const allToursUniqueCategories = arrayCombineUnique(toursCategories)

setFilters(parseQueryFilters(this.props.location.search))
setFilters({ ...pageContext.filters, allHotelCategories: allHotelsUniqueCategories, allTourCategories: allToursUniqueCategories })

}

render () {
const { data } = this.props

return (
  <Layout>
    <ItemGroups data={data} />
  </Layout>
)

}
}

/********************

  • REDUX
    ********************/

const mapDispatchTopProps = {
setFilters: filtersActions.setFilters
}

export default connect(null, mapDispatchTopProps)(FiltersPage)

/********************

  • GRAPHQL
    ********************/
    export const pageQuery = graphql query FiltersPage($country: String!) { allFirestoreTour(filter: { country: { eq: $country } }) { edges { node { id title country location region intro categories days collection coverImage fields { slug countrySlug } } } } allFirestoreTrip(filter: { country: { eq: $country } }) { edges { node { id title country location region intro collection coverImage fields { slug countrySlug } } } } allFirestoreHotel(filter: { country: { eq: $country } }) { edges { node { id title country location region intro categories coverImage stars collection fields { slug countrySlug } } } } }

Usual gatsby build command:
`node --max_old_space_size=8196 ./node_modules/.bin/gatsby build`

### Expected result

Compilation should be successful as it was in v1

### Actual result

Full build log:
```success open and validate gatsby-config โ€” 0.008 s
success onPreBootstrap โ€” 0.133 s
success delete html and css files from previous builds โ€” 6.535 s
success copy gatsby files โ€” 0.013 s
โข€ source and transform nodes -> wordpress__POST fetched : 1
โก€ source and transform nodes -> wordpress__PAGE fetched : 6
โ  source and transform nodes -> wordpress__wp_media fetched : 15
โ   source and transform nodes -> wordpress__wp_blocks fetched : 0
โ „ source and transform nodes -> wordpress__wp_jp_pay_order fetched : 0
โ ˆ source and transform nodes -> wordpress__wp_jp_pay_product fetched : 0
โข€ source and transform nodes -> wordpress__wp_feedback fetched : 0
โ ‚ source and transform nodes -> wordpress__wp_types fetched : 1
โ  source and transform nodes -> wordpress__wp_statuses fetched : 1
โก€ source and transform nodes -> wordpress__wp_taxonomies fetched : 1
โ  source and transform nodes -> wordpress__CATEGORY fetched : 4
โ   source and transform nodes -> wordpress__TAG fetched : 1
โ „ source and transform nodes -> wordpress__wp_users fetched : 3
โ ˆ source and transform nodes -> wordpress__wp_me fetched : 1
โข€ source and transform nodes -> wordpress__wp_comments fetched : 0
โ ‚ source and transform nodes -> wordpress__wp_settings fetched : 1
โ ‚ source and transform nodes -> wordpress__wp_credential fetched : 2
success source and transform nodes โ€” 12.415 s
success building schema โ€” 1.557 s
success createPages โ€” 3.742 s
success createPagesStatefully โ€” 0.193 s
success onPreExtractQueries โ€” 0.001 s
success update schema โ€” 1.071 s
warning There are conflicting field types in your data. GraphQL schema will omit those fields.
wordpress__wp_media.media_details.width:
 - type: number
   value: 4896
 - type: string
   value: '1600'
wordpress__wp_media.media_details.height:
 - type: number
   value: 2752
 - type: string
   value: '953'
firestoreTour.versions[].hotels[].hotelID:
 - type: number
   value: 0
 - type: string
   value: '204'
success extract queries from components โ€” 0.806 s
success run graphql queries โ€” 0.091 s
success write out page data โ€” 0.090 s
success write out redirect data โ€” 0.001 s
success onPostBootstrap โ€” 0.001 s

info bootstrap finished - 29.594 s

success Building production JavaScript and CSS bundles โ€” 101.468 s

error Building static HTML for pages failed

See our docs page on debugging HTML builds for help https://goo.gl/yL9lND

  38 |       var args = [a, b, c, d, e, f];
  39 |       var argIndex = 0;
> 40 |       error = new Error(
     | ^
  41 |         format.replace(/%s/g, function() { return args[argIndex++]; })
  42 |       );
  43 |       error.name = 'Invariant Violation';


  WebpackError: Invariant Violation: Could not find "store" in either the context or props of "Connect(FiltersPage)".   Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(FiltersPage)".

  - invariant.js:40 invariant
    [lib]/[invariant]/invariant.js:40:1

  - connectAdvanced.js:117 new Connect
    [lib]/[react-redux]/es/components/connectAdvanced.js:117:1

  - react-dom-server.node.production.min.js:26 d
    [lib]/[react-dom]/cjs/react-dom-server.node.production.min.js:26:314

  - react-dom-server.node.production.min.js:28 wa
    [lib]/[react-dom]/cjs/react-dom-server.node.production.min.js:28:493

  - react-dom-server.node.production.min.js:33 a../node_modules/react-dom/cjs/react-dom-server.node.production.min.js.    a.render
    [lib]/[react-dom]/cjs/react-dom-server.node.production.min.js:33:46

  - react-dom-server.node.production.min.js:32 a../node_modules/react-dom/cjs/react-dom-server.node.production.min.js.    a.read
    [lib]/[react-dom]/cjs/react-dom-server.node.production.min.js:32:246

  - react-dom-server.node.production.min.js:43 renderToString
    [lib]/[react-dom]/cjs/react-dom-server.node.production.min.js:43:1

  - static-entry.js:170 Object._default [as default]
    lib/.cache/static-entry.js:170:16

  - bootstrap:12 Worker.Queue [as fn]
    lib/webpack/bootstrap:12:1

  - bootstrap:58 Worker.start
    lib/webpack/bootstrap:58:1


  - gatsby-browser-entry.js:36 
    lib/.cache/gatsby-browser-entry.js:36:7

  - bootstrap:76 MemoryStore.getLock
    lib/webpack/bootstrap:76:1


  - bootstrap:58 MemoryStore.takeFirstN
    lib/webpack/bootstrap:58:1

  - find-page.js:27 Queue._getNextBatch
    lib/.cache/find-page.js:27:7

Environment

  System:
    OS: Linux 4.17 Solus 3.9999
    CPU: x64 Intel(R) Core(TM) i7-2820QM CPU @ 2.30GHz
    Shell: 4.4.19 - /bin/bash
  Binaries:
    Node: 8.11.3 - /usr/bin/node
    Yarn: 1.7.0 - /usr/bin/yarn
    npm: 5.6.0 - /usr/bin/npm
  Browsers:
    Firefox: 61.0
  npmPackages:
    gatsby: next => 2.0.0-beta.13 
    gatsby-cli: next => 2.0.0-beta.3 
    gatsby-paginate: next => 1.0.16 
    gatsby-plugin-less: next => 2.0.0-beta.3 
    gatsby-plugin-react-helmet: next => 3.0.0-beta.3 
    gatsby-source-firebase: next => 1.0.0 
    gatsby-source-firestore: next => 1.0.2 
    gatsby-source-wordpress: next => 3.0.0-beta.4 
  npmGlobalPackages:
    gatsby-cli: 1.1.58

File contents (if changed)

gatsby-browser.js:
```import React from 'react'
import { Router } from 'react-router-dom'
import { Provider } from 'react-redux'
import firebase from 'firebase/app'

import createStore from './src/state/createStore'
import { loadState, saveState } from './src/state/localStorage'

const config = {
apiKey: 'AIzaSyC4PU0ILY45uZ3oDe5Y4S-w6go1dRVHF4E',
authDomain: 'tourasia-ch.firebaseapp.com',
databaseURL: 'https://tourasia-ch.firebaseio.com',
projectId: 'tourasia-ch',
storageBucket: 'tourasia-ch.appspot.com',
messagingSenderId: '712966527886'
}
firebase.initializeApp(config)

const persistedState = loadState()

export const replaceRouterComponent = ({ history }) => {
const store = createStore(persistedState)

store.subscribe(() => {
saveState({
wishlist: store.getState().wishlist
})
})

const ConnectedRouterWrapper = ({ children }) => (


)

return ConnectedRouterWrapper
}


`gatsby-ssr.js`: 
```import React from 'react'
import { Provider } from 'react-redux'
import { renderToString } from 'react-dom/server'

import createStore from './src/state/createStore'

exports.replaceRenderer = ({ bodyComponent, replaceBodyHTMLString }) => {
  const store = createStore()

  const ConnectedBody = () => (
    <Provider store={store}>
      {bodyComponent}
    </Provider>
  )
  replaceBodyHTMLString(renderToString(<ConnectedBody />))
}
question or discussion

Most helpful comment

In my situation im forced to use both gatsby-browser and gatsby-ssr, if i do not usegatsby-ssr` develop will work without issue but build WILL NOT.

gatsby-ssr is required for build regardless if you plan to support SSR

https://github.com/gatsbyjs/gatsby/tree/master/examples/using-redux

All 16 comments

Does it work if you replace exports.replaceRenderer with export const replaceRenderer? If so, Gatsby should provide more helpful errors for this as part of the fix for #4718.

Edit: see also https://next.gatsbyjs.org/docs/migrating-from-v1-to-v2/#convert-to-either-pure-commonjs-or-pure-es6

This is good tip, but unfortunetaly after applying changes error still persist... Any other ideas ?

@m-allanson I think I got it. When I remove redux connect from page component everything builds. So it seems that u cannot export gatsby page graphql query along with react redux HOC connect... Is this known and default behavior for v2 ?

EDIT:

This works:

import React from 'react'
import { graphql } from 'gatsby'

import Layout from '../components/Layouts/homepage'

const IndexPage = ({ data }) => {
  return (
    <Layout>
      test
    </Layout>
  )
}

export default IndexPage

/**************************************************************
 * GRAPHQL
 **************************************************************/
export const pageQuery = graphql`
  query FilterQuery {
    wordpressPost {
      wordpress_id
      date(formatString: "Do MMMM YYYY")
      slug
      title
      content
      author {
        name
      }
      featured_media {
        source_url
      }
      excerpt
    }
  }
`

This don't:

import React from 'react'
import { connect } from 'react-redux'
import { graphql } from 'gatsby'

import Layout from '../components/Layouts/homepage'

const IndexPage = ({ data }) => {
  return (
    <Layout>
      test
    </Layout>
  )
}

export default connect()(IndexPage)

/**************************************************************
 * GRAPHQL
 **************************************************************/
export const pageQuery = graphql`
  query FilterQuery {
    wordpressPost {
      wordpress_id
      date(formatString: "Do MMMM YYYY")
      slug
      title
      content
      author {
        name
      }
      featured_media {
        source_url
      }
      excerpt
    }
  }
`

Hmm that doesn't seem like expected behaviour. Any chance you could put together a little demo repo for this issue?

I was able to add Redux to my Gatsby-v2 application with attaching the provider to my layout component, and connect to my header component, However when adding connect to a page component, i received the same error.

A quick work around is to have a custom connect component:

import React from 'react'
import { connect } from "react-redux";
import store from '../redux/store'

const connectWithStore = (mapStateToProps = null, mapDispatchToProps = null, mergeProps = null) => WrappedComponent =>{
    const ConnectedWrappedComponent = connect(mapStateToProps,mapDispatchToProps,mergeProps)(WrappedComponent)
  return props => <ConnectedWrappedComponent {...props} store={store} />
}

export default connectWithStore

Usage:
export default connectWithStore(mapStateToProps,mapDispatchToProps)(index)

https://github.com/reduxjs/react-redux/issues/390

@m-allanson as he mentioned above, replaceexports.replaceRenderer with export const replaceRenderer both gatsby-browser.js and gatsby-ssr.js

@gapgag55 Im not using either of those config folders currently. Also the ReplaceRender api can only be used in gatsby-ssr and im not doing any ssr so im dont see this as a valid option. please clarify if im wrong thanks.

@dirtyredz I do something like below (only implemented in gatsby-browser.js is okay)

export const replaceRouterComponent = ({ history }) => {
  const store = createStore();

  const ConnectedRouterWrapper = ({ children }) => (
    <Provider store={store}>
      <Router history={history}>{children}</Router>
    </Provider>
  );

  ConnectedRouterWrapper.propTypes = {
    children: PropTypes.element.isRequired,
  };

  return ConnectedRouterWrapper;
};

In my situation im forced to use both gatsby-browser and gatsby-ssr, if i do not usegatsby-ssr` develop will work without issue but build WILL NOT.

gatsby-ssr is required for build regardless if you plan to support SSR

https://github.com/gatsbyjs/gatsby/tree/master/examples/using-redux

I am seeing a very similar issue except I am using apollo instead of redux.

I am using Gatsby v2. My src/pages/index.tsx is:

import React from 'react'
import { Query } from 'react-apollo';
import gql from 'graphql-tag';

const eventsQuery = gql`
query {
    listEvents(limit: 10) {
        items {
            id
            name
            where
            when
            description
        }
    }
}
`;

export default () => (
    <Query query={eventsQuery}>
        {({ data, loading, error }) => {
            if (!data || !data.listEvents || !data.listEvents.items) {
                return null;
            }

            return (
                <div>
                    <pre>
                        {JSON.stringify(data.listEvents.items, null, 2)}
                    </pre>
                </div>
            );
        }}
    </Query>
);

My gatsby-browser.js is:

import React from 'react'
import { Router } from 'react-router-dom'
import { ApolloProvider } from 'react-apollo';
import { client } from './src/apolloClient';

export const replaceRouterComponent = ({ history }) => {

    const ConnectedRouterWrapper = ({ children }) => (
        <ApolloProvider client={client}>
            <Router history={history}>{children}</Router>
        </ApolloProvider>
    )

    return ConnectedRouterWrapper
}

and my gatsby-ssr.js is:

import React from 'react';
import { renderToString } from 'react-dom/server';
import { MockedProvider } from 'react-apollo/test-utils';

export const replaceRenderer = ({ bodyComponent, replaceBodyHTMLString }) => {
    const ConnectedBody = () => (
        <MockedProvider>
            {bodyComponent}
        </MockedProvider>
    );
    const result = renderToString(<ConnectedBody />);

    replaceBodyHTMLString(result);
};

When I gatsby build, I get:

success Building production JavaScript and CSS bundles โ€” 6.174 s

error Building static HTML for pages failed

See our docs page on debugging HTML builds for help https://goo.gl/yL9lND

  38 |       var args = [a, b, c, d, e, f];
  39 |       var argIndex = 0;
> 40 |       error = new Error(
     | ^
  41 |         format.replace(/%s/g, function() { return args[argIndex++]; })
  42 |       );
  43 |       error.name = 'Invariant Violation';


  WebpackError: Invariant Violation: Could not find "client" in the context of Query or as passed props. Wrap the root component in an <ApolloProvider>

  - invariant.js:40 invariant
    [lib]/[invariant]/invariant.js:40:1

However, if I move the MockedProvider into src/pages/index.tsx, then it builds ok:

export default () => (
    <MockedProvider>
        <Query query={eventsQuery}>
            {({ data, loading, error }) => {
                if (!data || !data.listEvents || !data.listEvents.items) {
                    return null;
                }

                return (
                    <div>
                        <pre>
                            {JSON.stringify(data.listEvents.items, null, 2)}
                        </pre>
                    </div>
                );
            }}
        </Query>
    </MockedProvider>
);

but of course I can't use Apollo. If I conditionally wrap with MockedProvider based on typeof window === 'undefined, then I get a fully working site in both develop and build modes.

This is with Gatsby v2, I will try v1 right now.

When using Gatsby v1 (via gatsby new mysite https://github.com/gatsbyjs/gatsby-starter-hello-world), then the above works just fine.

This seems to be a general React Context issue. This tiny Gatsby app repro's the issue without Redux or Apollo: https://github.com/city41/gatsbyv2-context-issue~~

My suspicion is Gatsby V2 is executing React components before gatsby-ssr.js gets a chance to kick in, so these components are throwing due to missing the context prop they need.

I have no idea and will shut up now. After playing around with this for a while, I started from scratch and built up a gatsby v2 site using apollo and this one works just fine.

Due to the high volume of issues, we're closing out older ones without recent activity. Please open a new issue if you need help!

Note to self and someone facing the same issue:
@dirtyredz's comment worked for me.

I just copied my gatsby-browser.js that is working well in devServer into gatsby-ssr.js. I used wrapRootElement instead of replaceRenderer.

A better and DRY example is here:
https://github.com/gatsbyjs/gatsby/tree/ec8deb2d757524316a06ae3cefe26d7626549ad6/examples/using-redux

Note to self and someone facing the same issue:
@dirtyredz's comment worked for me.

I just copied my gatsby-browser.js that is working well in devServer into gatsby-ssr.js. I used wrapRootElement instead of replaceRenderer.

A better and DRY example is here:
https://github.com/gatsbyjs/gatsby/tree/ec8deb2d757524316a06ae3cefe26d7626549ad6/examples/using-redux

Hey, do you have a example of this? I have the same issue but sadly nothing suggested so far worked - https://github.com/gatsbyjs/gatsby/issues/13934 <-- is my issue in more detail

I got an issue like this. I don't know if it's the same as this one, but the fix was weird...

This is how my gatsby-ssr.js looked like:

export function wrapRootElement({ element }) {
  const initialState = calculateInitialState();
  const store = configureStore(initialState);
  return (
    <App store={store}>{element}</App>
  );
}

The problem appeared to be with that fact that I did export function rather than export const.

By doing this instead, it worked:

export const wrapRootElement = ({ element }) => {
  const initialState = calculateInitialState();
  const store = configureStore(initialState);
  return (
    <App store={store}>{element}</App>
  );
};

I don't get it why export function doesn't work, even though it worked fine to use export function in gatsby-browser.js.

I wonder if this might relate to #13667; though I didn't use CommonJS syntax, just export function instead of export const.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

timbrandin picture timbrandin  ยท  3Comments

dustinhorton picture dustinhorton  ยท  3Comments

ferMartz picture ferMartz  ยท  3Comments

jimfilippou picture jimfilippou  ยท  3Comments

dustinhorton picture dustinhorton  ยท  3Comments