diff --git a/docs/docs/migrating-from-v1-to-v2.md b/docs/docs/migrating-from-v1-to-v2.md index 8075d4acbc59a..b546007187dea 100644 --- a/docs/docs/migrating-from-v1-to-v2.md +++ b/docs/docs/migrating-from-v1-to-v2.md @@ -29,6 +29,7 @@ This is a reference for upgrading your site from Gatsby v1 to Gatsby v2. While t - [APIs onPreRouteUpdate and onRouteUpdate no longer called with the route update action](#apis-onprerouteupdate-and-onrouteupdate-no-longer-called-with-the-route-update-action) - [Browser API `replaceRouterComponent` was removed](#browser-api-replaceroutercomponent-was-removed) - [Browser API `replaceHistory` was removed](#browser-api-replacehistory-was-removed) + - [Browser API `wrapRootComponent` was replaced with `wrapRootElement`](#browser-api-wraprootcomponent-was-replaced-with-wraprootelement) - [Don't query nodes by ID](#dont-query-nodes-by-id) - [Use Query in place of RootQueryType](#use-query-in-place-of-rootquerytype) - [Typography.js Plugin Config](#typographyjs-plugin-config-changes) @@ -122,7 +123,8 @@ In Gatsby v2, the special layout component (`src/layouts/index.js`) that wrapped There are a number of implications to this change: - To render different layouts for different pages, just use the standard React inheritance model. Gatsby no longer maintains, or needs to maintain, separate behavior for handling layouts. -- Because the "top level component" changes between each page, React will rerender all children. This means that shared components previously in a Gatsby v1 layout-- like navigations-- will unmount and remount. This will break CSS transitions or React state within those shared components. For more information, including in-progress workarounds, [see this ongoing discussion](https://github.com/gatsbyjs/gatsby/issues/6127). +- Because the "top level component" changes between each page, React will rerender all children. This means that shared components previously in a Gatsby v1 layout-- like navigations-- will unmount and remount. This will break CSS transitions or React state within those shared components. If your use case requires layout component to not unmount use [`gatsby-plugin-layout`](https://www.gatsbyjs.org/packages/gatsby-plugin-layout/). + - To learn more about the original decisions behind this removal, read the [RFC for removing the special layout component](https://github.com/gatsbyjs/rfcs/blob/master/text/0002-remove-special-layout-components.md). The following migration path is recommended: @@ -542,7 +544,27 @@ React Router allowed you to swap out its history object. To enable this in Gatsb We did, erroneously, suggest using this API for adding support for Redux, etc. where you need to wrap the root Gatsby component with your own component. If you were using `replaceRouterComponent` for this, you'll need to migrate to -`wrapRootComponent`. See this PR migrating the `using-redux` example site as a pattern to follow https://github.com/gatsbyjs/gatsby/pull/6986 +`wrapRootElement`: + +```diff +import React from 'react' +import { Provider } from 'react-redux' +-import { Router } from 'react-router-dom' + +-export const replaceRouterComponent = ({ history }) => { ++export const wrapRootElement = ({ element }) => { +- const ConnectedRouterWrapper = ({ children }) => ( ++ const ConnectedRootElement = ( + +- {children} ++ {element} + + ) + +- return ConnectedRouterWrapper ++ return ConnectedRootElement +} +``` ### Browser API `replaceHistory` was removed @@ -874,6 +896,26 @@ Import graphql types from `gatsby/graphql` to prevent `Schema must contain uniqu +const { GraphQLString } = require(`gatsby/graphql`) ``` +### Browser API `wrapRootComponent` was replaced with `wrapRootElement` + +Use new [`wrapRootElement`](/docs/browser-apis/#wrapRootComponent) API: +We now pass `component` Element instead of `Root` Component and expect that `wrapRootElement` will return Element and not Component. This change was needed to keep all wrapping APIs uniform. + +```diff +-export const wrapRootComponent = ({ Root }) => { ++export const wrapRootElement = ({ element }) => { +- const ConnectedRootComponent = () => ( ++ const ConnectedRootElement = ( + +- ++ {element} + + ) +- return ConnectedRootComponent ++ return ConnectedRootElement +} +``` + ## For Explorers ### Starting a New Project with v2 diff --git a/examples/using-multiple-providers/gatsby-config.js b/examples/using-multiple-providers/gatsby-config.js new file mode 100644 index 0000000000000..cdf4ec94a2566 --- /dev/null +++ b/examples/using-multiple-providers/gatsby-config.js @@ -0,0 +1,11 @@ +module.exports = { + siteMetadata: { + title: `Gatsby with multiple providers`, + }, + plugins: [ + `gatsby-plugin-jss`, + `gatsby-plugin-styled-components`, + `gatsby-plugin-redux`, + `gatsby-plugin-apollo-client`, + ], +} diff --git a/examples/using-multiple-providers/package.json b/examples/using-multiple-providers/package.json new file mode 100644 index 0000000000000..5fc764f645de7 --- /dev/null +++ b/examples/using-multiple-providers/package.json @@ -0,0 +1,32 @@ +{ + "name": "gatsby-example-using-multiple-providers", + "private": true, + "description": "Gatsby example site using multiple plugins implementing wrapping APIs", + "version": "1.0.0", + "author": "Michal Piechowiak ", + "dependencies": { + "apollo-boost": "^0.1.13", + "babel-plugin-styled-components": "^1.5.1", + "gatsby": "next", + "gatsby-plugin-jss": "next", + "gatsby-plugin-styled-components": "next", + "isomorphic-fetch": "^2.2.1", + "react": "^16.4.0", + "react-apollo": "^2.1.11", + "react-dom": "^16.4.0", + "react-jss": "^8.6.1", + "react-redux": "^5.0.7", + "redux": "^4.0.0", + "styled-components": "^3.4.2" + }, + "keywords": [ + "gatsby" + ], + "license": "MIT", + "main": "n/a", + "scripts": { + "develop": "gatsby develop", + "build": "gatsby build", + "serve": "gatsby serve" + } +} diff --git a/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/gatsby-browser.js b/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/gatsby-browser.js new file mode 100644 index 0000000000000..522be4c879a80 --- /dev/null +++ b/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/gatsby-browser.js @@ -0,0 +1,2 @@ +const preferDefault = m => (m && m.default) || m +exports.wrapRootElement = preferDefault(require(`./inject-provider`)) diff --git a/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/gatsby-ssr.js b/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/gatsby-ssr.js new file mode 100644 index 0000000000000..9aa3de057bdf2 --- /dev/null +++ b/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/gatsby-ssr.js @@ -0,0 +1,4 @@ +require(`isomorphic-fetch`) + +const preferDefault = m => (m && m.default) || m +exports.wrapRootElement = preferDefault(require(`./inject-provider`)) diff --git a/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/inject-provider.js b/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/inject-provider.js new file mode 100644 index 0000000000000..eb73b8e03d303 --- /dev/null +++ b/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/inject-provider.js @@ -0,0 +1,12 @@ +import React from "react" +import ApolloClient from "apollo-boost" +import { ApolloProvider } from "react-apollo" + +const client = new ApolloClient({ + uri: `https://api-euwest.graphcms.com/v1/cjjr1at6d0xb801c3scjrm0l0/master`, +}) + +// eslint-disable-next-line react/prop-types,react/display-name +export default ({ element }) => ( + {element} +) diff --git a/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/package.json b/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/package.json new file mode 100644 index 0000000000000..9e26dfeeb6e64 --- /dev/null +++ b/examples/using-multiple-providers/plugins/gatsby-plugin-apollo-client/package.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/examples/using-multiple-providers/plugins/gatsby-plugin-redux/gatsby-browser.js b/examples/using-multiple-providers/plugins/gatsby-plugin-redux/gatsby-browser.js new file mode 100644 index 0000000000000..2bb44b9d6e3a5 --- /dev/null +++ b/examples/using-multiple-providers/plugins/gatsby-plugin-redux/gatsby-browser.js @@ -0,0 +1 @@ +exports.wrapRootElement = require(`./inject-provider`) diff --git a/examples/using-multiple-providers/plugins/gatsby-plugin-redux/gatsby-ssr.js b/examples/using-multiple-providers/plugins/gatsby-plugin-redux/gatsby-ssr.js new file mode 100644 index 0000000000000..2bb44b9d6e3a5 --- /dev/null +++ b/examples/using-multiple-providers/plugins/gatsby-plugin-redux/gatsby-ssr.js @@ -0,0 +1 @@ +exports.wrapRootElement = require(`./inject-provider`) diff --git a/examples/using-multiple-providers/plugins/gatsby-plugin-redux/inject-provider.js b/examples/using-multiple-providers/plugins/gatsby-plugin-redux/inject-provider.js new file mode 100644 index 0000000000000..074e580a35f66 --- /dev/null +++ b/examples/using-multiple-providers/plugins/gatsby-plugin-redux/inject-provider.js @@ -0,0 +1,16 @@ +const React = require(`react`) +const { Provider } = require(`react-redux`) +const { createStore } = require(`redux`) + +const reducer = (state, action) => { + if (action.type === `SET_BLOG_POST`) { + return action.payload + } + return state +} + +const initialState = { id: null, title: `None` } +const store = createStore(reducer, initialState) + +// eslint-disable-next-line react/prop-types,react/display-name +module.exports = ({ element }) => {element} diff --git a/examples/using-multiple-providers/plugins/gatsby-plugin-redux/package.json b/examples/using-multiple-providers/plugins/gatsby-plugin-redux/package.json new file mode 100644 index 0000000000000..9e26dfeeb6e64 --- /dev/null +++ b/examples/using-multiple-providers/plugins/gatsby-plugin-redux/package.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/examples/using-multiple-providers/src/pages/index.js b/examples/using-multiple-providers/src/pages/index.js new file mode 100644 index 0000000000000..95fc911aa103c --- /dev/null +++ b/examples/using-multiple-providers/src/pages/index.js @@ -0,0 +1,112 @@ +import React from "react" +import { connect } from "react-redux" +import styled from "styled-components" +import { gql } from "apollo-boost" +import { Query } from "react-apollo" +import injectSheet from "react-jss" + +const styles = { + listItem: { + cursor: `pointer`, + fontSize: `1.5em`, + color: `blue`, + textDecoration: `underline`, + }, +} + +const Counter = styled.p` + color: palevioletred; +` + +const GET_POSTS = gql` + query { + blogPosts { + id + title + } + } +` + +const GET_POST = gql` + query($id: ID) { + blogPost(where: { id: $id }) { + title + post + } + } +` + +class IndexPage extends React.Component { + render() { + return ( +
+

Multiple provider-example

+

Redux component:

+ + ReduxState: +
{JSON.stringify(this.props.reduxState)}
+
+

Apollo

+

List (click on something)

+ + {({ loading, error, data }) => { + if (loading) return
Loading...
+ if (error) return
Error :(
+ + return ( +
    + {data.blogPosts.map(data => { + const { id, title } = data + return ( +
  • { + this.props.setBlogPost(data) + }} + key={id} + > + {title} +
  • + ) + })} +
+ ) + }} +
+ {this.props.reduxState.id && ( + + {({ loading, error, data }) => { + if (loading) return
Loading...
+ if (error) return
Error :(
+ + return ( + <> +

Details {data.blogPost.title}

+
{data.blogPost.post}
+ + ) + }} +
+ )} +
+ ) + } +} + +const mapStateToProps = state => { + return { reduxState: state } +} + +const mapDispatchToProps = dispatch => { + return { + setBlogPost: blogPost => + dispatch({ type: `SET_BLOG_POST`, payload: blogPost }), + } +} + +const ReduxConnectedIndexPage = connect( + mapStateToProps, + mapDispatchToProps +)(IndexPage) + +export default injectSheet(styles)(ReduxConnectedIndexPage) diff --git a/examples/using-redux/gatsby-browser.js b/examples/using-redux/gatsby-browser.js index dd8cbdd2bc212..11a9e4b298258 100644 --- a/examples/using-redux/gatsby-browser.js +++ b/examples/using-redux/gatsby-browser.js @@ -1,16 +1,2 @@ -import React from "react" -import { Provider } from "react-redux" - -import createStore from "./src/state/createStore" - -const store = createStore() - -export const wrapRootComponent = ({ Root }) => { - const ConnectedRootComponent = () => ( - - - - ) - - return ConnectedRootComponent -} +import wrapWithProvider from "./wrap-with-provider" +export const wrapRootElement = wrapWithProvider diff --git a/examples/using-redux/gatsby-ssr.js b/examples/using-redux/gatsby-ssr.js index 5d615775ab0fe..11a9e4b298258 100644 --- a/examples/using-redux/gatsby-ssr.js +++ b/examples/using-redux/gatsby-ssr.js @@ -1,16 +1,2 @@ -import React from 'react' -import { Provider } from 'react-redux' -import { renderToString } from 'react-dom/server' - -import createStore from './src/state/createStore' - -export const replaceRenderer = ({ bodyComponent, replaceBodyHTMLString }) => { - const store = createStore() - - const ConnectedBody = () => ( - - {bodyComponent} - - ) - replaceBodyHTMLString(renderToString()) -} +import wrapWithProvider from "./wrap-with-provider" +export const wrapRootElement = wrapWithProvider diff --git a/examples/using-redux/wrap-with-provider.js b/examples/using-redux/wrap-with-provider.js new file mode 100644 index 0000000000000..9ff9b365ad23a --- /dev/null +++ b/examples/using-redux/wrap-with-provider.js @@ -0,0 +1,9 @@ +import React from "react" +import { Provider } from "react-redux" + +import createStore from "./src/state/createStore" + +const store = createStore() + +// eslint-disable-next-line react/display-name,react/prop-types +export default ({ element }) => {element} diff --git a/examples/using-styletron/gatsby-config.js b/examples/using-styletron/gatsby-config.js index fffe864e0a341..f15e6d2d2f2ed 100644 --- a/examples/using-styletron/gatsby-config.js +++ b/examples/using-styletron/gatsby-config.js @@ -2,14 +2,5 @@ module.exports = { siteMetadata: { title: `Gatsby with Styletron`, }, - plugins: [ - `gatsby-plugin-styletron`, - { - resolve: `gatsby-plugin-google-analytics`, - options: { - trackingId: `UA-93349937-2`, - }, - }, - `gatsby-plugin-offline`, - ], + plugins: [`gatsby-plugin-styletron`], } diff --git a/examples/using-styletron/package.json b/examples/using-styletron/package.json index 572ac7dd0b703..bd666ce8283c4 100644 --- a/examples/using-styletron/package.json +++ b/examples/using-styletron/package.json @@ -6,20 +6,9 @@ "author": "Nadiia Dmytrenko ", "dependencies": { "gatsby": "next", - "gatsby-plugin-google-analytics": "next", - "gatsby-plugin-offline": "next", "gatsby-plugin-styletron": "next", - "lodash": "^4.16.4", "react": "^16.4.0", - "react-dom": "^16.4.0", - "react-typography": "^0.15.0", - "slash": "^1.0.0", - "styletron-engine-atomic": "^1", - "styletron-react": "^4", - "styletron-react-core": "^1", - "styletron-standard": "^1", - "typography": "^0.15.8", - "typography-breakpoint-constants": "^0.14.0" + "react-dom": "^16.4.0" }, "keywords": [ "gatsby" diff --git a/examples/using-styletron/src/utils/typography.js b/examples/using-styletron/src/utils/typography.js deleted file mode 100644 index f070170c7faef..0000000000000 --- a/examples/using-styletron/src/utils/typography.js +++ /dev/null @@ -1,40 +0,0 @@ -import Typography from "typography" -import { - MOBILE_MEDIA_QUERY, - TABLET_MEDIA_QUERY, -} from "typography-breakpoint-constants" - -const options = { - baseFontSize: `18px`, - baseLineHeight: 1.45, - blockMarginBottom: 0.75, - scaleRatio: 2.15, - overrideStyles: ({ rhythm, scale }, options) => { - return { - "h1,h2,h3,h4": { - lineHeight: 1.2, - }, - [TABLET_MEDIA_QUERY]: { - // Make baseFontSize on mobile 17px. - html: { - fontSize: `${(17 / 16) * 100}%`, - }, - }, - [MOBILE_MEDIA_QUERY]: { - // Make baseFontSize on mobile 16px. - html: { - fontSize: `${(16 / 16) * 100}%`, - }, - }, - } - }, -} - -const typography = new Typography(options) - -// Hot reload typography in development. -if (process.env.NODE_ENV !== `production`) { - typography.injectStyles() -} - -export default typography diff --git a/packages/gatsby-plugin-jss/src/gatsby-browser.js b/packages/gatsby-plugin-jss/src/gatsby-browser.js index db22b93d92901..f672735eac78d 100644 --- a/packages/gatsby-plugin-jss/src/gatsby-browser.js +++ b/packages/gatsby-plugin-jss/src/gatsby-browser.js @@ -3,16 +3,11 @@ const ThemeProvider = require(`react-jss`).ThemeProvider // remove the JSS style tag generated on the server to avoid conflicts with the one added on the client exports.onInitialClientRender = () => { - // eslint-disable-next-line no-undef const ssStyles = window.document.getElementById(`server-side-jss`) ssStyles && ssStyles.parentNode.removeChild(ssStyles) } - -exports.wrapRootComponent = ({ Root }, options) => () => { +// eslint-disable-next-line react/prop-types +exports.wrapRootElement = ({ element }, options) => { const theme = options.theme || {} - return ( - - - - ) + return {element} } diff --git a/packages/gatsby-plugin-jss/src/gatsby-ssr.js b/packages/gatsby-plugin-jss/src/gatsby-ssr.js index 696a7988f5bb4..096c613bab113 100644 --- a/packages/gatsby-plugin-jss/src/gatsby-ssr.js +++ b/packages/gatsby-plugin-jss/src/gatsby-ssr.js @@ -1,20 +1,16 @@ import React from "react" -import { renderToString } from "react-dom/server" import { JssProvider, SheetsRegistry, ThemeProvider } from "react-jss" -exports.replaceRenderer = ( - { bodyComponent, replaceBodyHTMLString, setHeadComponents }, - { theme = {} } -) => { - const sheets = new SheetsRegistry() +const sheets = new SheetsRegistry() - const bodyHTML = renderToString( - - {bodyComponent} - - ) +// eslint-disable-next-line react/prop-types,react/display-name +exports.wrapRootElement = ({ element }, { theme = {} }) => ( + + {element} + +) - replaceBodyHTMLString(bodyHTML) +exports.onRenderBody = ({ setHeadComponents }) => { setHeadComponents([