Closed aamorozov closed 6 years ago
@aamorozov would you be able to put together a reproduction? It really helps us dive in much more quickly, and it's a big time saver for us.
Thank you!
Sure - I'll create a setup matching to my project as close as possible during the day @DSchau
Thanks so much! I do feel like there are similar issues to this, so we may merge this issue with one of those once we learn more!
e.g. see #1836
I have never used jsxstyle, but I had a similar issue with material-ui.
The problem for me was that in Gatsby, each page produces a separate html tree, so the material-ui class-name generator was assigning the same class name to different components on different pages.
Material-ui has an option to customize the generated class prefix, so my solution was to use a different prefix for each page. Not sure if jsxstyle has a similar configuration option.
Data point: Like @appleJax , I too have this issue when using material-ui
.
Edit: @DSchau this can be reproduced here: https://github.com/AryanJ-NYC/webdev-coach-blog
@AryanJ-NYC @aamorozov you can also create client-side routes with the @reach/router
package. I think this is the recommended way? https://www.gatsbyjs.org/docs/building-apps-with-gatsby/
I ended up not using a withStyles
material-ui
method call and all is well.
@AryanJ-NYC if you want to use withStyles
on multiple pages, just pass a unique prefix as a prop to the Layout
component and forward it to JssProvider
. Looking at your repo, you'd modify the Layout
component like this:
// Layout.js
const TemplateWrapper = ({ children, classes, classPrefix }) => {
const generateClassName = createGenerateClassName({
productionPrefix: classPrefix
});
return (
<>
<Helmet title="The WebDev Coach" />
<JssProvider generateClassName={generateClassName}>
// ...
</JssProvider>
</>
);
});
And then instantiate Layout
like so:
// about-page.js
const AboutPage = () => <Layout classPrefix='ap'> { /* ... */ } </Layout>
@appleJax 🙏 🙏 🙏
Update (in case anyone comes looking for help): I just ended up following the material-ui gatsby example: https://github.com/mui-org/material-ui/tree/master/examples/gatsby
@DSchau Sorry for the delay, here is a repo to reproduce https://github.com/aamorozov/gatsby-jsxstyle-issue. To replicate:
yarn build && yarn serve
http://localhost:9000
- the images are in a columnLeaving here if anyone else stumbles up on the same issue while using Gatsby v2 + Material UI; I had to remove withRoot
from all child components and have just one withRoot
HOC per page as mentioned here
@aamorozov I cloned your repo and tested it out. There is a line that you forgot to delete in pages/index.js
(the Section
component doesn't exist):
// src/pages/index.js
import Section from '../components/section';
After I deleted that line, I ran yarn build && yarn serve
, navigated to localhost:9000
, and everything looked normal, with the images in a row. I navigated back and forth from /
to /page-2.
, and everything remained consistent.
Can you confirm your reproduction repo does not display the correct styles on the initial page load?
My environment is almost the same as yours:
OS: macOS High Sierra 10.13.6
Node: 10.12.0
Yarn: 1.10.1
npm: 6.4.1
Browsers Tested:
- Chrome: 70.0.3538.67
- Firefox: 63.0
- Safari: 11.1.2
@appleJax I just updated the repo and removed that component. The environment is indeed the same. I do notice now that the issue persists, but is not happening on every recompile. If I run yarn build the first time it might show me the correct layout, but I tried rebuilding a few times, with/without removing the old cache and it showed me the issue on 2nd rebuild...
@aamorozov I think I've found a fix. Let me know if this works for you. I think gatsby-plugin-jsxstyle
is using the wrong ssr API. Try making the following change to node_modules/gatsby-plugin-jsxstyle/gatsby-ssr.js
:
// node_modules/gatsby-plugin-jsxstyle/gatsby-ssr.js
// Change this line
// exports.onRenderBody = ({ setHeadComponents }) => {
// To this
exports.replaceRenderer = ({ setHeadComponents }) => {
@appleJax
Unfortunately, it didn't work. The issue still persists randomly on the repro project and is constant on the actual project where the codebase is bigger. Thank you for the effort, i will keep looking - i think it's an issue either within the gatsby-plugin-jsxstyle
or jsxstyle-webpack-plugin
and not necessarily related to gatsby itself..
@aamorozov I think you're right, jsxstyle-webpack-plugin
seems to be non-deterministic with class-name generation. This will at least make the class names deterministic:
// node_modules/gatsby-plugin-jsxstyle/gatsby-node.js
// Change this line
// use: [JsxstylePlugin.loader],
// To this
use: [{
loader: JsxstylePlugin.loader,
options: {
classNameFormat: 'hash'
}
}]
It fixes the issue for your reproduction repo, but it's hard to tell with such a small codebase. Let me know if it works for your larger project.
Hi, maintainer of jsxstyle here. I am not familiar with the specifics of how Gatsby caches stuff between builds, but if the issue is that Gatsby doesn’t render things in a single webpack build then there will most definitely be issues with mismatched/missing styles. Each stylesheet is unique to each build. However, there is a (not very well documented) option to keep an on-disk cache of the groups of styles that jsxstyle has seen. This cache file ensures that groups of styles are keyed with the same index regardless of webpack’s module iteration order. This allows users to use the shorter CSS classname format while keeping builds deterministic.
Ideally this cache file would be located in the .cache
folder. I managed to get it working with the following:
const JsxstylePlugin = require('jsxstyle-webpack-plugin');
const path = require('path');
exports.onCreateWebpackConfig = ({ store, actions }) => {
const { program } = store.getState();
actions.setWebpackConfig({
plugins: [new JsxstylePlugin()],
module: {
rules: [
{
test: /\.(?:jsx?|tsx)$/,
use: [
{
loader: JsxstylePlugin.loader,
options: {
cacheFile: path.resolve(
program.directory,
'.cache',
'jsxstyle-cache.txt'
),
},
},
],
},
],
},
});
};
While I was digging around in the .cache
folder I saw a subfolder called caches
that already has a folder for gatsby-plugin-jsxstyle
. Is that cache folder path accessible from onCreateWebpackConfig
?
Ah neat, looks like Gatsby passes a Cache
instance to each plugin function:
This seems to do the trick:
const JsxstylePlugin = require('jsxstyle-webpack-plugin');
const path = require('path');
exports.onCreateWebpackConfig = ({ actions, cache }) => {
actions.setWebpackConfig({
plugins: [new JsxstylePlugin()],
module: {
rules: [
{
test: /\.(?:jsx?|tsx)$/,
use: [
{
loader: JsxstylePlugin.loader,
options: {
cacheFile: path.resolve(cache.directory, 'style-key-cache.txt'),
},
},
],
},
],
},
});
};
Since this issue is an implementation bug (fixed in https://github.com/jsxstyle/jsxstyle/pull/123, thx @aamorozov) I’d say it can be closed here.
Bugfix PR has been merged and published. Thanks!
Closing the issue since it was addressed in jsxstyle project
@appleJax
I've followed your approach to have unique class prefix in each page by passing the prefix to Layout
Component but I still have the class problem - about-us
page has contact-us
prefix.
Any idea?
@DavidHe1127 I'd have to see your code to know what you're doing wrong. If you post a link to your repo, I can take a look. The class-prefix trick was just my little hacky solution. I think best practice would be to follow the official MUI gatsby example found here: https://github.com/mui-org/material-ui/tree/master/examples/gatsby
@appleJax Thanks for your response. I actually overwrite createPages
api provided by Gatsby to create pages using templates. Not sure if that matters. But anyway, I can show you my code snippets below.
layout.js
import React from 'react';
import PropTypes from 'prop-types';
import { StaticQuery, graphql } from 'gatsby';
import styled from 'styled-components';
import JssProvider from 'react-jss/lib/JssProvider';
import { createGenerateClassName } from '@material-ui/core/styles';
import PageHeader from 'components/common/PageHeader';
import PageFooter from 'components/common/PageFooter';
import './layout.css';
const ContentContainer = styled.div`
min-height: 100vh;
overflow: hidden;
display: block;
position: relative;
padding-bottom: 80px;
`;
const Layout = ({ children, classPrefix }) => {
const generateClassName = createGenerateClassName({
productionPrefix: classPrefix,
});
return (
<StaticQuery
query={graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`}
render={data => (
<JssProvider generateClassName={generateClassName}>
<ContentContainer>
<PageHeader siteTitle={data.site.siteMetadata.title} />
<div>{children}</div>
<PageFooter />
</ContentContainer>
</JssProvider>
)}
/>
);
};
Layout.propTypes = {
children: PropTypes.node.isRequired,
};
export default Layout;
templates/contact-us.js
import React from 'react';
import styled from 'styled-components';
import { withStyles } from '@material-ui/core/styles';
import { Link, graphql } from 'gatsby';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';
import TextField from '@material-ui/core/TextField';
import Email from '@material-ui/icons/Email';
import Geolocation from '@material-ui/icons/Room';
import Phone from '@material-ui/icons/Phone';
import Form from 'components/contactUs/Form';
import Layout from 'components/layout';
import CompanyInfor from 'components/contactUs/CompanyInfor';
import Button from 'components/common/Button';
import SEO from 'components/seo';
const Header = styled.div`
display: inline-block;
width: 100%;
height: 270px;
background-color: #5d6d7e;
padding: 48px;
margin-bottom: 48px;
`;
const Title = styled.h2`
margin-top: 20px;
font-size: 44px;
font-weight: bold;
color: #fff;
text-align: center;
`;
const styles = theme => ({
input: {
marginTop: 24,
marginBottom: 24,
marginLeft: 16,
marginRight: 16,
minWidth: 450,
'&:focus': {
borderColor: '#777',
},
},
cssOutlinedInput: {
'&$cssFocused $notchedOutline': {
borderColor: '#777',
},
},
cssLabel: {
'&$cssFocused': {
color: '#777',
},
},
cssFocused: {},
notchedOutline: {},
formTitle: {
marginLeft: 16,
},
icon: {
fontSize: 32,
},
});
const ContactUs = ({ data, classes }) => {
const {
markdownRemark: { frontmatter: content },
} = data;
const getInTouch = content.get_in_touch_with_us;
const inputProps = {
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
};
const inputLabelProps = {
classes: {
root: classes.cssLabel,
focused: classes.cssFocused,
},
};
return (
<Layout classPrefix="contact-us">
<SEO {...content.metadata} />
<Header>
<Title>{getInTouch.header}</Title>
</Header>
<TextField
label="Name"
className={classes.input}
margin="normal"
variant="outlined"
InputLabelProps={inputLabelProps}
InputProps={inputProps}
/>
</Layout>
);
};
export default withStyles(styles)(ContactUs);
export const ContactUsQuery = graphql`
query($id: String!) {
markdownRemark(id: { eq: $id }) {
frontmatter {
title
get_in_touch_with_us {
header
subheader
email
phone
}
metadata {
title
description
}
_PARENT
}
}
}
`;
gatsby-node.js
const path = require('path');
// Implement the Gatsby API “createPages”. This is called once the
// data layer is bootstrapped to let plugins create pages from data.
exports.createPages = ({ actions, graphql }) => {
const { createPage } = actions;
return graphql(`
query General {
allMarkdownRemark {
edges {
node {
id
frontmatter {
templateKey
_PARENT
}
}
}
}
}
`).then(result => {
if (result.errors) {
result.errors.forEach(e => console.error(e.toString()));
return Promise.reject(result.errors);
}
const pages = result.data.allMarkdownRemark.edges;
pages
.filter(edge => edge.node.frontmatter.templateKey !== 'index')
.forEach(edge => {
const id = edge.node.id;
const why_choose_us = edge.node.frontmatter.why_choose_us;
const {
node: {
frontmatter: { templateKey },
},
} = edge;
createPage({
path: `/${templateKey}`,
component: path.resolve(`src/templates/${templateKey}.js`),
context: {
id,
},
});
});
});
};
Let me know if you need anything else.
Thanks
@appleJax Problems solved after following material-ui + gatsby example. But I am still confused with their solution.
// This is needed in order to deduplicate the injection of CSS in the page.
sheetsManager: new Map(),
// This is needed in order to inject the critical CSS.
sheetsRegistry: new SheetsRegistry(),
I assume css are collected from components and injected into html during build time? Why do we need to dedupe here?
@DavidHe1127 can you please show a snippet on how you imported and used withRoot
?. ..
Am having errors using it with gatsby
@vickywane what errors did you get?
Sorry for the late reply .
I used the withRoot
from the MUI repo to wrap it but i get this error .
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
It worked with a next js
project i recently concluded( without using withRoot
)
Im really just starting out with web dev, so I might be wrong. Having said that, Im building a gatsby site with Material UI and was experiencing the same issues. Styles not being injected when loading site at index page, but after going to another page where the same component can be found styles are loaded correctly, and if you go back to the index page you now see everything correctly.
I tried a couple of things, but what solved it was adding to my gatsby-config.js the following:
{ resolve: 'gatsby-plugin-material-ui', // If you want to use styled components you should change the injection order. options: { stylesProvider: { injectFirst: true, }, },
Dont really understand much, except mi site is now working correctly.
Hey, I have the same issue, but I just follow this guide https://www.gatsbyjs.org/packages/gatsby-plugin-styled-components/?=styled and now my website is working correctly.
Regards.
Hey, I have the same issue, but I just follow this guide https://www.gatsbyjs.org/packages/gatsby-plugin-styled-components/?=styled and now my website is working correctly.
Regards.
Hey, thanks @chri5bot ! My site is working because of this as well.
Im really just starting out with web dev, so I might be wrong. Having said that, Im building a gatsby site with Material UI and was experiencing the same issues. Styles not being injected when loading site at index page, but after going to another page where the same component can be found styles are loaded correctly, and if you go back to the index page you now see everything correctly.
I tried a couple of things, but what solved it was adding to my gatsby-config.js the following:
{ resolve: 'gatsby-plugin-material-ui', // If you want to use styled components you should change the injection order. options: { stylesProvider: { injectFirst: true, }, },
Dont really understand much, except mi site is now working correctly.
This works. In my case I had a double call for the material UI plugin in the gatsby.config.js and the first one was not in this format {response... Newest version of the plugin and this works.
Hey, I have the same issue, but I just follow this guide https://www.gatsbyjs.org/packages/gatsby-plugin-styled-components/?=styled and now my website is working correctly.
Regards.
Hey, thank you so much for this :)
Can confirm, as @chri5bot stated, if you are using styled-components
, installing gatsby-plugin-styled-components
as well as babel-plugin-styled-components
should do the tricks.
Had similar issue for like a week, and now my app is working like a charm. 👍🏼
Can confirm, as @chri5bot stated, if you are using
styled-components
, installinggatsby-plugin-styled-components
as well asbabel-plugin-styled-components
should do the tricks.Had similar issue for like a week, and now my app is working like a charm. 👍🏼
Had the same problem with styled-components and installing the gatsby-plugin-styled-components did the trick for me!
I'm using a starter project that uses gatsby-plugin-emotion
, but seeing that content is rendered unstyled for a second or 2. I tried installing the gatby-plugin-styled-components
on top of that and it didn't seem to have any effect. Would the emotion
plugin interfere with this? The starter errors out when I switch everything to styled-components
as they're using some emotion
features.
@rebeccapeltz i really would suggest you stick to either emotion or styled-components. I figured out some styling bugs only pop up after you run build.
Your comment wasnt 100% clear. Do you have the styling error?
I removed the styled-components
code so it's just emotion
. In this video I refresh several times and you can see a flash where it shows the page unstyled content and even the icons are rendered unstyled. I like this starter and I'm glad to find this problem so I can better understand how to make this work. I don't see this problem running the app locally so it's something to do with the server-side render. https://www.screencast.com/t/2HrXbcAs
Hi,
I just saw where you said you remove all styled-components.
I dont have much experience using emotion
with gatsby. Do follow the steps above of you consider using styled-components
.
Thanks for your attention here. After adding the styled component dependencies and adding the plugin to gatsby.config.js, would I need to replace all the emotion code and remove the emotion plugin? Or is it possible to run them on the same project? In the responses above, there's no mention of code changes. It may be that I can't fix this starter app without some significant recoding. It does sound like I shouldn't expect to see the unstyled content though.
I do not have much experience with emotion
, however elements that are wrapped with styled-components shouldn't show as unstyled as you have shown.
I would advice you follow the documentation written at the plugin section of the docs and you make little incremental changes i.e trying styled-components on a component and see if it renders that same way before migrating everything.
You can leave a link to repository and i might have a look after my working hours.
Also just to test, you can comment out the emotion plugin line in your config
file , dont use the emotion styles for a particular component and try that component with styled-components and see if that works out.
I found this starter project. If you add some markdown under the content and push to netlify you'll get the same effect. I tried removing emotion and replacing with styled-components, but there are some code dependencies I don't understand. Do you know of another starter that produces a similar git book? https://github.com/hasura/gatsby-gitbook-starter. I really appreciate you looking into this.
Hey @rebeccapeltz. I used the same git-book https://condescending-pike-950821.netlify.app/ and I have the same problem. I was reading about this topic but I didn't find a good solution . Maybe It would help with something:
https://github.com/emotion-js/emotion/issues/1332
Could you try it?
let me know if it works.
Regards :)
I took out the react-helmet and it did seem unnecessary. When I deploy to netlify it still shows the unstyled lists before final render. I think if you're looking at 'gatsby develop', you won't see the problem, only when deployed on netlify. I'm trying to remove emotion
from the Layout component. It's using an Emotion Theme Provider to give the feature that allows you to control background color. Thanks for finding the fact that you don't need to React-Helmet!
Had the same problem, with style not loading initially (it created a really awful visual glitch).
I use JSS to style my components, and because the gatbsy-plugin-jss doesn’t offer ways to configure my own global style sheet, at some point I completely removed the plugin from my project and did the configuration manually in my gatsby-browser.js
I added the plugin back. Adding that one line in gatsby-config.js
, without changing anything to my gatsby-browser.js
solved the problem as well:
plugins: [
… // other plugins
`gatsby-plugin-jss`
]
I had some issues on my application that uses gatsby alongside MUI (gatsby-theme-material-ui
). My problem turned out to be with loading a value from a cookie in order to render a component. I solved the issue by loading the cookie value instead from a useEffect
hook. This approach was based on this issue comment: https://github.com/gatsbyjs/gatsby/issues/8560#issuecomment-599154610
Hey, I have the same issue, but I just follow this guide https://www.gatsbyjs.org/packages/gatsby-plugin-styled-components/?=styled and now my website is working correctly.
Regards.
I also had this issue and resolved it by simply installing gatsby-plugin-styled-components as per the above message.
The issue arose around the time I installed react-awesome-reveal, which is a library that uses Emotion in the background to do the animations on reveal. Another user above referred to Emotion during their issue so I suppose this is related.
Im really just starting out with web dev, so I might be wrong. Having said that, Im building a gatsby site with Material UI and was experiencing the same issues. Styles not being injected when loading site at index page, but after going to another page where the same component can be found styles are loaded correctly, and if you go back to the index page you now see everything correctly.
I tried a couple of things, but what solved it was adding to my gatsby-config.js the following:
{ resolve: 'gatsby-plugin-material-ui', // If you want to use styled components you should change the injection order. options: { stylesProvider: { injectFirst: true, }, },
Dont really understand much, except mi site is now working correctly.
Thank you so much for this!
This is a great thread! I'm wondering if anyone experiencing this problem with emotion has come up with a reliable solution? My problem seems isolated to components that combine css
and withTheme
from @emotion/react
and styled
from @emotion/styled
. Per the common descriptions here, initially many components load unstyled, but styles pop-in on browser refresh.
Each component looks like
components
|- AppBar
|- AppBar.jsx // exports UnstyledAppBar functional component
|- styles.js // exports styles() which returns css`...`
|- index.js // exports withTheme(styled(UnstyledAppBar)`${styles}`), i.e. a styled component with theme injected
Further, the styles that fail to work on first load are the styles derived from the theme
prop.
In other words
// styles.js
const styles = (props) => {
const { theme } = props;
return css`
margin-left: 24px;
margin-right: ${spacingSizeMedium}; // evaluates to 24px
`;
}
The margin-left
style renders immediately but margin-right
requires refresh.
This issue does not appear in Gatsby development mode, but occurs in Gatsby builds.
Description
Currently, when running
gatsby build && gatsby serve
and navigating to the page where the site is being served, some of the styles are not loading initially. However, if I navigate to any page within the app - it loads all the styles correctly. I am trying to isolate which exactly styles are not loaded, but there are no console/network errors at the moment.I am using jsxstyle. There are no issues when running dev build.
Steps to reproduce
This is happening in a private organization project, but I can put together a repo to reproduce.
Expected result
All styles are loaded on initial page load.
Actual result
Some of the styles are not loaded initially.
Environment