Closed alexandcote closed 6 years ago
Can you share how you load your styles? Is is plain css, styled components or something else?
Ah, itโs the example code? You donโt load any other styles?
Yeah the example code, no other styles was added. I think the styles are inject in the HTML when the component is loaded.
Thanks for your help ๐
This is a razzle problem i think. However, I don't have a great answer for you. Open to PR's though.
@alexandcote Hmm, is it possible these issues are related? https://github.com/jaredpalmer/after.js/issues/120
On the server, while material-ui does put out class names on elements, it does not output styles in the header. I get the same unstyled to styled flicker when reloading the page.
EDIT: Ignore me, the issue still exists without async component, so it's a material-ui issue.
@krazyjakee you can try to remove the lazy loading on the home component.
From
{
path: "/",
exact: true,
component: asyncComponent({
loader: () => import("./Home"), // required
Placeholder: () => <div>...LOADING...</div> // this is optional, just returns null by default
})
},
To
{
path: "/",
exact: true,
component: Home
}
Let me know if it resolve your problem
@alexandcote sorry, I didn't think to test this first. It did not resolve the problem so it's not the same issue.
In After.js here, is this only client side rendered?
If you disable javascript you can see that it renders the Home component contents but only the initial client css that is imported in client.js
Tested in Razzle with javascript disabled and page loads with styles as expected so might be an After.js problem?
@garmeeh I think it's a problem with asyncComponent
. I try to figure how we can fix this but for now I didn't find a solution. If anyone have a idea, let me know โ๏ธ
@alexandcote This is actually a "problem" with webpack, where css chunks are not handled well when imported from a module that is imported with a dynamic import()
. You actually need a plugin to handle those chunks.
Might actually be a good idea if after.js would use this by default. After all, code splitting and SSR is the point here. I'll look into it.
But, you could also just go around that problem and use one of the many css-in-jsโข solution at your disposal!
I highly suggest JSS.
I tested with JSS like @Madumo suggest and it worked perfectly ! Thanks again ๐ Maybe we should change the example to use JSS @jaredpalmer ?
@Madumo makes sense alright. I think this is a Razzle issue rather than after.js since it's building the server etc.
I do think it would be great to have this by default. Currently using extract-css-chunks-webpack-plugin
on another project and it means having to use react-universal-component as well. Adding this to Razzle wouldn't be trivial from my understanding on how to implement it.
This is a Razzle issue. However, with latest alpha's of razzle, we use mini-css-extract. Let's move this issue over there.
This still seems to be an issue purely with the lazy loading of a component. As @alexandcote states https://github.com/jaredpalmer/after.js/issues/118#issuecomment-375350142
When you make the component not lazy load you do not get the FOUC.
I'm importing a static css file e.g import 'my-stylesheet.css'
and this ends up client side rendering instead leading to flash of unstyle content.
I've noticed with the other Razzle examples the CSS file is including on the SSR side, so its definitly the lazy loading side of things associated with After.js asyncComponent()
additionally when the lazy load kicks in the css file is not outputted to the assets.json to be included.
Any ideas?
It is actually not related to asyncComponent
directly. It is webpack behavior to exlude .css
files are inside the .js
files which are lazily loaded. When we run npm run build
, we can see more then one css file are built.
In my case I am loading ./Home
file lazily in App.js
file.
App.js
import './App.css'
import './tailwind.css'
import React from 'react'
import Route from 'react-router-dom/Route'
import Switch from 'react-router-dom/Switch'
import Loadable from 'react-loadable'
const Home = Loadable({
loader: () => import('./Home'),
loading: () => null,
})
const App = () => (
<Switch>
<Route exact path="/" component={Home} />
</Switch>
)
when I run npm run build
i got following.
build command result (please note, two .css
files are here.)
Second chunk build\static\css\1.bundle.ca7057dd.css
contains ./Home.css
contents.
44.79 KB build\static\js\bundle.a50ceeae.js
6.56 KB build\static\js\2.17674f1a.chunk.js
819 B build\static\css\bundle.cf147a1e.css --- main --
622 B build\static\js\1.862187fa.chunk.js
261 B build\static\css\1.bundle.ca7057dd.css -- with home.css --
assets.json
Our assets.json
file contains the link of first bundle from above list.
{
"client": {
"css": "/static/css/bundle.cf147a1e.css", // -- main --
"js": "/static/js/bundle.a50ceeae.js"
}
}
So flash will be noticed in production mode as second .css
is not getting referenced.
Html
<html lang="">
ย <head>
ย <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
ย <meta charSet='utf-8' />
ย <title>Welcome to Razzle</title>
ย <meta name="viewport" content="width=device-width, initial-scale=1">
ย <link rel="stylesheet" href="/static/css/bundle.5c3433c4.css"> <!-- main only -->
ย </head>
-----------
-----------
</html>
Solution
we need to explicitly include that .css
. Below is the link which explain how to handle server rendering with react-loadable.
https://github.com/jamiebuilds/react-loadable#how-do-i-handle-other-styles-css-or-sourcemaps-map-with-server-side-rendering.
@SheikhG1900 hey man can you please tell me how you got the other styles in the chunks ?
It seems like this was never resolved. I'm still seeing the flash behavior described by the OP. I'm using a vanilla install of afterjs, ran the production build and served it and I'm still seeing the flash.
@SheikhG1900 hey man can you please tell me how you got the other styles in the chunks ?
@heshamelmasry77 please check this code https://github.com/SheikhG1900/with-razzle/blob/73774e85bd28d1a579b9c9f8ca923d689312ed0e/src/server.tsx#L35-L51
It's bit ugly but I got to manage to work it with isomorphic-style-loader
.
At least, for style perspective, after.js should provide some way to inject additional header after in render
function.
But, it would be tricky as style
or link
tag can be provided after render finished...
We had very strange issues with certain classes not matching up on initial client render.
The fix was to use only react-dom/render in production but for development, only use hydrate after the initial mount.
I may still have a misunderstanding of how everything works but this fixed it for us. We have a very specific setup so this is pseudo code.
client.js
import React from 'react';
import { render, hydrate } from 'react-dom';
import { ensureReady } from '@jaredpalmer/after';
import After from '@jaredpalmer/after/After';
import routes from './routes';
ensureReady(routes).then(data => {
let renderMethod = render;
if (window.NODE_ENV === 'development') {
renderMethod = module.hot ? render : hydrate;
}
renderMethod(
<After data={data} routes={routes} />,
document.getElementById('root'),
() => {
const jssStyles = document.getElementById('jss-ssr');
if (jssStyles && jssStyles.parentNode) {
jssStyles.parentNode.removeChild(jssStyles);
}
}
);
});
if (module.hot) {
module.hot.accept();
}
From what I research, you may suffer for FOUC because your main css bundle does not include all the necessary styles (because your css is spit among entry). Digging into the code, it is marked as @todo https://github.com/jaredpalmer/razzle/blob/43160eb1cdbbe5b4353a714a3db7faba629a1bd3/packages/razzle/config/createConfig.js#L555
You can combine all css into 1 file inside your razzle.config.js
config.optimization = {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true,
},
},
},
}
You also need to change your html accordingly
Solution we need to explicitly include that
.css
. Below is the link which explain how to handle server rendering with react-loadable. https://github.com/jamiebuilds/react-loadable#how-do-i-handle-other-styles-css-or-sourcemaps-map-with-server-side-rendering.
@SheikhG1900 Is it possible to handle css chunks with asyncComponent from after.js? I tried to do it follow by instructions with react-loadable, but in this case method getInitialProps
of component doesn't execute.
it's too late I know, but we fixed this in #232 and it's going to get merged soon.
First of all, you are genius ! Thanks for all your libs ๐
I tested this lib during the weekend and it worked like a charm, I love the approach you propose. I'm wondering If you already had issue with brief flash of unstyled content. I found two other closed issues https://github.com/jaredpalmer/after.js/issues/104 and https://github.com/jaredpalmer/razzle/issues/307 but I think the issue still there with code splitting.
I made some tests and here the result:
Note here that both app run in production mode.
Lazy loaded Home component
No lazy loaded
Any idea how can I fix this and keep the code splitting ๐
Thanks a lot again for your time and work ๐ฅ