react-universally
react-universally copied to clipboard
styled-components improvement
Hello,
I made some tests with server side rendering and the styled components feature branch. Seems like the server side rendering doesn't work for the styles. Regarding to this discussions https://github.com/styled-components/styled-components/issues/124 I implemented this:
file: src/server/middleware/reactApplication/index.js
import styleSheet from 'styled-components/lib/models/StyleSheet'
...
// Create our React application and render it into a string.
const reactAppString = renderToString(
<CodeSplitProvider context={codeSplitContext}>
<ServerRouter location={request.url} context={reactRouterContext}>
<DemoApp />
</ServerRouter>
</CodeSplitProvider>,
);
const styles = styleSheet.rules().map(rule => rule.cssText).join('\n')
// Generate the html response.
const html = generateHTML({
// Provide the full app react element.
reactAppString,
// Nonce which allows us to safely declare inline scripts.
nonce,
// Running this gets all the helmet properties (e.g. headers/scripts/title etc)
// that need to be included within our html. It's based on the rendered app.
// @see https://github.com/nfl/react-helmet
helmet: Helmet.rewind(),
// We provide our code split state so that it can be included within the
// html, and then the client bundle can use this data to know which chunks/
// modules need to be rehydrated prior to the application being rendered.
codeSplitState: codeSplitContext.getState(),
styledComponents: styles,
});
Then I added them into
file: src/server/middleware/reactApplication/generateHTML.js
export default function generateHTML(args: Args) {
const { reactAppString, initialState, nonce, helmet, codeSplitState, styledComponents } = args;
...
return `<!DOCTYPE html>
<html ${helmet ? helmet.htmlAttributes.toString() : ''}>
<head>
${helmet ? helmet.title.toString() : ''}
${helmet ? helmet.meta.toString() : ''}
${helmet ? helmet.link.toString() : ''}
${styleTags(assetsForRender.css)}
<style>${styledComponents || ''}</style>
${helmet ? helmet.style.toString() : ''}
</head>
<body>
Looks now a lot nicer to me. Can someone confirm that this is a good solution? :) Thanks
It's a start. More information on styled-components SSR @ https://github.com/styled-components/styled-components/pull/214
Thanks for looking into this @datoml :)
I'll have a review of this soon. :)
The glamor styleSheet
that styled-components exposes is a singleton.With the above approach every request to render a page will result in it's styles being appended to it.So in subsequent requests you end up sending previously rendered CSS unrelated to the current page.
Calling styleSheet.flush()
in between requests doesn't seem to work at the moment.
Has someone got a full working implementation that they are willing to create a PR for?
I am currently using styled-components for my project with the hope that there will be a fix in die near future for this. @ctrlplusb I am not that familiar with creating a PRs :).
@datoml I encourage you to try!
Check out this cool egghead course: How to Contribute to an Open Source Project on GitHub
Thanks for the link. I'll have a look :):
@ctrlplusb I implemented the SSR changed that @datoml recommended above, you can check it out here. It seems to work, but it double injects the styles, once on the server and once on the client.
I'm wondering if you read what i linked. That's all known and discussed and there's no solution for it yet, even though it's very simple in principle https://github.com/styled-components/styled-components/pull/214
I did. We currently have to wait that this gets implemented. Everything here is currently a workaround until its done and gets released.
FYI I have been using styletron
, which has no problems with SSR and has a similar API to styled-components. In case this is blocking someones adoption, there are alternatives.
I tried styletron but I like the api from styled-components more. Doing something like this feels awesome to me :).
import styled from 'styled-components';
const button = styled.button`
color: green;
border: 1px solid blue;
`;
I'm hard to convince as well. On the one hand i'm not sure about the performance implications of styletrons many CSS selectors in really large DOMs (think Githubs Diff view), on the other hand i love to be able to write CSS instead of objects, including inline syntax highlighting etc, so i'm with @datoml on that one :)
Totally see your guys points, I guess I prefer the object style as it opens up the Javascript as the API to modifying/merging styles:
const centeredButtonStyle = Object.assign(
{},
{ color: 'red' },
theme.layout.centered
);
I have been really enjoying creating and composing objects for more generic styles.
Thats true. The reason styled-components won my heart was that I can copy the whole css and go back to good old css styles. Every approach has it pros and cons tho :).
Check this out: https://github.com/RafalFilipek/styled-props
:)
I will have a look on it :). But it seems similar to the build in ThemeProvider. https://github.com/styled-components/styled-components#theming
Or am I missing something? :D
@codepunkt Thanks for suggesting styletron, i was totally unaware of it's existence....:P
@ctrlplusb @codepunkt Server Rendering API for styled-components
has just been merged into master
@lucianlature it was merged into v2
branch, not master
.
Got too excited for a moment, sorry.
Out of curiosity, did you guys look at https://github.com/rofrischmann/fela According to https://github.com/hellofresh/css-in-js-perf-tests it is extremely fast and creates very small sized output compared to something like glamor/styletron. The docs are great (http://fela.js.org/docs/guides/UsageWithReact.html), it works with react-native, and SSR is implemented and works too.
And with https://github.com/jakecoxon/babel-plugin-css-to-js you can have a very similar API to styled-components!
@bkniffler The alternatives are endless. CSS in JSS fatigue! 🤣
In order to get styled-components working server-side with current v2-beta, which api seems still a bit under discussion (https://github.com/styled-components/styled-components/pull/214), you can use this approach.
https://gist.github.com/mschipperheyn/c17280278218074a53147f54259af66a
The reference keyword is: styledComponentCSS
I based this on react-universally@next
Does anybody have styled components working with react universally nowadays? I am using version 2.1.1 of styled components, but have not had any joy. I looked at the gist provided by 'mschipperheyn', but it looks like things have changed in styled-components land!
I am trying to use ServerStyleSheet, creating an instance and then using collectStyles on my app component. But I am missing something, getStyleElement returns an empty array. I know that app is async so perhaps at the point of collection it is empty?
Okay, I was on the right track. I managed to implement Styled Components by passing my ServerStyleSheet instance as a prop on ServerHTML, then using .getStyleElement() to add the css to headerElements within ServerHTML.js. I am really pleased I got this working and also pleased I found React Universally.
@designspin is there a gist you could share if it all works? Btw, here is the main issue on styled-components where you could also maybe post that update for others following the issue - https://github.com/styled-components/styled-components/issues/762
@oyeanuj
Here is a GIST of what appears to be working for me right now: https://gist.github.com/designspin/c11095334ae1f105d1f93123232d37fd
@designspin If you will link me a repo where you're having issues, I'll take a look.
@strues
No issue, the above GIST is in fact a solution. It is working for me, thanks.