After reading the documentation about gatsby-browser.js
(https://www.gatsbyjs.org/docs/browser-apis/#wrapRootElement) and wrapRootElement, I figured after seeing that it's best suited for Providers to use it for my emotion ThemeProvider
from the emotion-theming
package (see https://github.com/emotion-js/emotion/tree/master/packages/emotion-theming).
This is how my gatsby-browser.js file looks like:
import React from 'react';
import { ThemeProvider } from './src/context/ThemeContext';
export const wrapRootElement = ({ element }) => (
<ThemeProvider>{element}</ThemeProvider>
);
ThemeContext basically wraps the emotion theme provider with some other feature and is located in src/context/
import React from 'react';
import themeDark from '../theme_dark';
import themeLight from '../theme_light';
const defaultState = {
dark: false,
themeLoaded: themeLight,
toggleDark: () => {},
};
const ThemeContext = React.createContext(defaultState);
const supportsDarkMode = () =>
window.matchMedia('(prefers-color-scheme: dark)').matches === true;
class ThemeProvider extends React.Component {
state = {
dark: false,
};
toggleDark = () => {
let dark = !this.state.dark;
localStorage.setItem('dark', JSON.stringify(dark));
this.setState({ dark });
};
componentDidMount() {
// Getting dark mode value from localStorage!
const lsDark = JSON.parse(localStorage.getItem('dark'));
if (lsDark) {
this.setState({ dark: lsDark });
} else if (supportsDarkMode()) {
this.setState({ dark: true });
}
}
render() {
const { children } = this.props;
const { dark } = this.state;
let themeLoaded = themeLight;
if (dark) {
themeLoaded = themeDark;
}
return (
<ThemeContext.Provider
value={{
themeLoaded,
dark,
toggleDark: this.toggleDark,
}}
>
{children}
</ThemeContext.Provider>
);
}
}
export default ThemeContext;
export { ThemeProvider };
When running yarn develop
I see no problem. The theme is injected as expected.
However thois doesn't work when running yarn build
:
โฏ yarn build
yarn run v1.13.0
$ gatsby build
success open and validate gatsby-configs โ 0.011 s
success load plugins โ 0.191 s
success onPreInit โ 0.413 s
success delete html and css files from previous builds โ 0.122 s
success initialize cache โ 0.004 s
success copy gatsby files โ 0.083 s
success onPreBootstrap โ 0.011 s
success source and transform nodes โ 0.055 s
success building schema โ 0.221 s
success createPages โ 1.881 s
success createPagesStatefully โ 0.029 s
success onPreExtractQueries โ 0.086 s
success update schema โ 0.206 s
success extract queries from components โ 0.120 s
success run graphql queries โ 0.050 s โ 11/11 228.11 queries/second
success write out page data โ 0.003 s
success write out redirect data โ 0.001 s
success onPostBootstrap โ 0.002 s
info bootstrap finished - 4.97 s
success Building production JavaScript and CSS bundles โ 8.873 s
โ Building static HTML for pages{ theme: {},
style: { marginBottom: '50px' },
children:
[ { '$$typeof': Symbol(react.element),
type: [Function],
key: null,
ref: null,
props: [Object],
_owner: null },
{ '$$typeof': Symbol(react.element),
type: [Function],
key: null,
ref: null,
props: [Object],
_owner: null },
{ '$$typeof': Symbol(react.element),
type: [Function],
key: null,
ref: null,
props: [Object],
_owner: null },
{ '$$typeof': Symbol(react.element),
type: [Function],
key: null,
ref: null,
props: [Object],
_owner: null } ] }
error Building static HTML for pages failed
See our docs page on debugging HTML builds for help https://gatsby.app/debug-html
4 |
5 | const BlackSectionWrapper = styled.div`
> 6 | background: ${props => props.theme.colors.black};
| ^
7 | position: relative;
8 | left: calc(-50vw + 50%);
9 | width: 100vw;
gatsby-browser.js
The build should pass. This pattern works in development
The build fails with the logs above
System:
OS: macOS 10.14.1
CPU: (4) x64 Intel(R) Core(TM) i7-7567U CPU @ 3.50GHz
Shell: 5.3 - /bin/zsh
Binaries:
Node: 10.12.0 - /usr/local/bin/node
Yarn: 1.13.0 - /usr/local/bin/yarn
npm: 6.7.0 - /usr/local/bin/npm
Browsers:
Chrome: 71.0.3578.98
Firefox: 63.0.3
Safari: 12.0.1
npmPackages:
gatsby: ^2.0.76 => 2.0.98
gatsby-image: ^2.0.20 => 2.0.28
gatsby-mdx: ^0.3.2 => 0.3.5
gatsby-plugin-emotion: ^4.0.1 => 4.0.1
gatsby-plugin-google-analytics: ^2.0.9 => 2.0.10
gatsby-plugin-manifest: ^2.0.9 => 2.0.13
gatsby-plugin-offline: ^2.0.16 => 2.0.21
gatsby-plugin-react-helmet: ^3.0.2 => 3.0.5
gatsby-plugin-sharp: ^2.0.14 => 2.0.18
gatsby-plugin-sitemap: ^2.0.4 => 2.0.4
gatsby-plugin-tslint: ^0.0.2 => 0.0.2
gatsby-plugin-typescript: ^2.0.3 => 2.0.3
gatsby-plugin-typography: ^2.2.5 => 2.2.5
gatsby-remark-autolink-headers: ^2.0.12 => 2.0.12
gatsby-remark-images: ^3.0.1 => 3.0.1
gatsby-source-filesystem: ^2.0.8 => 2.0.17
gatsby-transformer-sharp: ^2.1.8 => 2.1.12
Where is your ThemeContext.Consumer
located?
https://www.gatsbyjs.org/blog/2019-01-31-using-react-context-api-with-gatsby/#editing-the-layout-file
ThemeContext.Consumer
is used in my src/pages/index.js
(this file doesn't use any layout at the moment, maybe this is why it's failing?) and in my src/layout/index.js
I'd recommend adding your ThemeProvider
as the top level element in our Layout
component and using the Layout
component as the top level element of your page files.
Yeah that definitely works. However since I have multiple layouts I hoped that I could use gatsby-browser as the single entry point to pass my ThemeProvider
No worries. What do your theme files look like? Can you show an example of your consumer being used?
Hey, you need to add equivalent Providers in gatsby-ssr.js
:
import React from 'react';
import { ThemeProvider } from './src/context/ThemeContext';
export const wrapRootElement = ({ element }) => (
<ThemeProvider>{element}</ThemeProvider>
);
I think we need to expand documentation on those - that usually you would need to add this in both places and it would not be the case only some subtle edge cases
@dakebl here's an example of one of my Themes:
const white = '#FFFFFF';
const black = '#161617'; // For background color
const blackFont = '#2B2D3E'; // For font color
const gray = '#F8F8F9';
const theme = {
backgroundColor: '#0e0e0e',
colors: {
black,
blackFont,
blue: '#3c83da',
gray,
pink: '#FED5D7',
white,
},
fontColor: white,
transitionTime: 0.5,
};
export default theme;
and here's an example on how it's being used in one of my layout files:
const Layout = (props: InterfaceLayoutProps) => (
<StaticQuery
query={graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
author
}
}
}
`}
render={data => {
const { frontmatter, cover, tableOfContents } = props.pageContext;
const { title, subtitle } = frontmatter;
return (
<ThemeContext.Consumer>
{(theme: {
dark: boolean;
themeLoaded: object;
toggleDark: () => void;
}) => (
<React.Fragment>
<SEO title={`${title} - ${data.site.siteMetadata.title}`} />
<Header
themeSwitcher={theme}
sticky={true}
siteTitle={data.site.siteMetadata.author}
/>
<LayoutWrapper>
<TitleSection>
<div>
<Title>{title}</Title>
<h2>{subtitle}</h2>
</div>
</TitleSection>
<div
style={{
margin: '0 auto',
maxHeight: '600px',
maxWidth: '1430px',
}}
>
<Img
imgStyle={{ maxHeight: '600px', minHeight: '300px' }}
fluid={cover.childImageSharp.fluid}
/>
</div>
<LayoutContentWrapper>
<MDXProvider
components={{
a: (aProps: any) => (
<a {...aProps} style={{ color: 'inherit' }} />
),
}}
>
{props.children}
</MDXProvider>
</LayoutContentWrapper>
</LayoutWrapper>
<Footer tableOfContents={tableOfContents} />
</React.Fragment>
)}
</ThemeContext.Consumer>
);
}}
/>
);
@pieh I'll give this a try as soon as I can
@pieh it worked! Making sure the content between gatsby-browser.js
and gatsby-ssr.js
is the same fixed the build error.
Thank you!
Adding providers to gatsby-ssr.js
also worked for me.
You can add the same Providers in gatsby-ssr.js and gatsby-browser.js the following way so you don't repeat code:
// gatsby-ssr.js
export { wrapRootElement } from './gatsby-browser'
Most helpful comment
Hey, you need to add equivalent Providers in
gatsby-ssr.js
:I think we need to expand documentation on those - that usually you would need to add this in both places and it would not be the case only some subtle edge cases