Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style definitions vary within server/client side rendering #705

Closed
jkempff opened this issue May 28, 2015 · 21 comments
Closed

Style definitions vary within server/client side rendering #705

jkempff opened this issue May 28, 2015 · 21 comments
Labels
package: styles Specific to @mui/styles. Legacy package, @material-ui/styled-engine is taking over in v5.

Comments

@jkempff
Copy link

jkempff commented May 28, 2015

I have a React app, that runs on the server and in the clients browser.

When I upgrade to v0.8.0, React gives me the "Expected html differs from the given markup" warning, because there are differences in the inline style definitions. For example:

Server renders:

style="...; user-select: none;.."

But the client (Chrome in this case) renders

style="...; -webkit-user-select: none;.."

While it is nice to not have to worry about vendor prefixes, the correct handling of them creates those differences. Does anyone have an idea on how to fix (or workaround) this? I dont want to send the client, perfectly good markup, and then let React rebuild half of it, because of that.

Maybe include all prefixes necessary? Might be tricky as well..

Or do I have to exclude all css that needs to be prefixed back into style sheets?

@pomerantsev
Copy link
Contributor

It would be nice if someone built a module that depended on autoprefixer or directly on caniuse-db that had a function like this:

  • get an unprefixed property name and value as parameters (for example, {key: 'transition', value: '1s linear transform'});
  • take options as an additional parameter ({ browsers: ['last 1 version'] });
  • spit out an array of all necessary key-value pairs: [{key: 'WebkitTransition', value: '1s linear -webkit-transform'}, {key: 'transition', value: '1s linear transform'}].

@jkempff
Copy link
Author

jkempff commented Jun 8, 2015

Could be tricky too.. afaik, autoprefixer only takes CSS as a string, and no objects or JSON.
You would have to turn the style object into CSS, run autoprefixer, and turn it back into a style object. However, this should be part of a build process, or somehow cachable.. I wouldn't want my app to do this on every page request.

@iyoukeyyewei
Copy link

I have the same problem. (client) 0;border-radius:2px;-webkit-user-select:
(server) 0;border-radius:2px;user-select:none;pos

any one can help?

@jkempff
Copy link
Author

jkempff commented Jun 14, 2015

atm I don't have a solution on this. For me it was downgrading to v0.7.3

@wmertens
Copy link

I don't see how there can be a solution. Either you generate the same code or you don't.

If you generate the same code, either you don't prefix and everything breaks, or you prefix in the same way.

To prefix in the same way, you either do it browser-neutral or browser-specific.

Browser-neutral means either pulling in a 2MB database for prefixing, or generating all prefixes for everything. Sucks on client side.

Browser-specific means doing it the way v0.8 does client side, and browser sniffing on the server side. Sucks on server side.

👉 If you don't generate the same code, all react will do is adjust the styles on the html on first load. Is that really such a problem?

@jkempff
Copy link
Author

jkempff commented Jun 30, 2015

As far as I know, React will not only add all missing components, but replace the entire DOM. But correct me if I'm wrong

@anuragsimgeker
Copy link

I ran into the same thing with fluxible.io. I'm currently looking at

<FlatButton label="Sign in"/>``` 

with the checksum error

(client) 0;border-radius:2px;-webkit-user-select:
(server) 0;border-radius:2px;user-select:none;pos

@DanielHeath
Copy link

This creates a ton of jank on page-load for isomorphic apps.

Replacing the entire DOM once the javascript arrives, especially on slower mobiles is just not a viable option.

Browser sniffing on the server is a non-starter as soon as you want to set a cache header (Vary: user-agent is going to bust your cache hard).

Front-end performance is more than just page weight.

@wmertens
Copy link

Ok, so that just leaves identifying the major culprits and moving them to
css, or changing React…

On Wed, Aug 19, 2015, 06:02 Daniel Heath [email protected] wrote:

This creates a ton of jank on page-load for isomorphic apps.

Replacing the entire DOM once the javascript arrives, especially on slower
mobiles is just not a viable option.

Browser sniffing on the server is a non-starter as soon as you want to set
a cache header (Vary: user-agent is going to bust your cache hard).

Front-end performance is more than just page weight.


Reply to this email directly or view it on GitHub
#705 (comment)
.

Wout.
(typed on mobile, excuse terseness)

@DanielHeath
Copy link

One of the main benefits of isomorphic apps is that the page looks right before the JS loads.

That benefit is somewhat lost if you only prefix on the client-side; half the CSS rules will be missing.

@manuelmazzuola
Copy link

Any updates ?

@Nic128
Copy link

Nic128 commented Oct 22, 2015

+1

@TheUltDev
Copy link
Contributor

I've been working on this. I'll have a PR soon.™

This is a fork of an inline prefixer library I found in a Radium issue discussion (they're having the same issue)
Currently my change is in a pull request to go further upstream, but you can check it out here:
https://github.com/Cavitt/inline-style-prefixer

The project initially is just for prefixing based on a user agent, which you can do.
However if you plan on rendering on the server before even knowing the user agent, you can specify * as the user agent.
This will build prefixes for all vendors (down to a configured supported version).

What's the catch? It doesn't work well with alternative css values.
So something like display: flex; => display: -ms-flexbox; won't happen.
Switch to a specific user agent, re-render the client, or don't use that css feature.
I've had great results with Material's doc site so far, so this shouldn't be a large issue.

import Prefixer from 'inline-style-prefixer';
import ImmutabilityHelper from '../utils/immutability-helper';

// Combine all vendor prefixes
let prefixer = new Prefixer('*');

module.exports = {

  all(styles) {
    return prefixer.prefix(styles)
  },

  set(style, key, value) {
    let mergedStyle = ImmutabilityHelper.merge.apply(this, prefixer.prefix({key: value}));
    return mergedStyle
  },

  single(key, value) {
    return prefixer.prefix({key: value})
  },

};

Further performance gains can be made by rendering all prefixes on the server and on the first client load,
but subsequent client changes can target the client's user agent.

@oliviertassinari
Copy link
Member

@Cavitt So the solution you propose compute the missing prefix at the run-time.
Looks like we have to add all the prefix without taking account the user-agent to make it work.
Hence, why not doing it a the build time (better perf I assume) with https://github.com/UXtemple/babel-plugin-react-autoprefix?

Still we have to consider #684, #1132

What's the catch? It doesn't work well with alternative CSS values.
So something like display: flex; => display: -ms-flexbox; won't happen.

Well babel-plugin-react-autoprefix does, see https://github.com/UXtemple/babel-plugin-react-autoprefix/blob/master/__tests__/index-test.es6#L37

@shaurya947 @hai-cea Thougts?

@aleksey-taranets
Copy link

Hello guys, any updates in the issue? We have implemented material ui and when switched to universal app got the issue. It's quite important for react development, maybe authors can give us vision of their next steps in this?

@wmertens
Copy link

So this just came out:
https://github.com/prometheusresearch/react-stylesheet

Seems like an interesting mix between defining styles in js and using
classes.

The only sane way to solve the server-side rendering issue is by using
classes.

On Mon, Oct 26, 2015, 1:51 PM Aleksey Taranets [email protected]
wrote:

Hello guys, any updates in the issue? We have implemented material ui and
when switched to universal app got the issue. It's quite important for
react development, maybe authors can give us vision of their next steps in
this?


Reply to this email directly or view it on GitHub
#705 (comment)
.

Wout.
(typed on mobile, excuse terseness)

@Ohskar
Copy link

Ohskar commented Oct 26, 2015

Excuse terseness!

Sent from my iPhone

On Oct 26, 2015, at 12:30 PM, Wout Mertens [email protected] wrote:

So this just came out:
https://github.com/prometheusresearch/react-stylesheet

Seems like an interesting mix between defining styles in js and using
classes.

The only sane way to solve the server-side rendering issue is by using
classes.

On Mon, Oct 26, 2015, 1:51 PM Aleksey Taranets [email protected]
wrote:

Hello guys, any updates in the issue? We have implemented material ui and
when switched to universal app got the issue. It's quite important for
react development, maybe authors can give us vision of their next steps in
this?


Reply to this email directly or view it on GitHub
#705 (comment)
.

Wout.
(typed on mobile, excuse terseness)

Reply to this email directly or view it on GitHub.

@TheUltDev
Copy link
Contributor

@oliviertassinari actually there shouldn't be any reason we can't use useragent when rendering on the server and client.
We should have access to that. The only time to use * would be for caching and fallback purposes (unrecognized useragent)

The missing prefixes are computed server-side like autoprefixer would do, but they're also able to be computed client side.
Which solves the issue.

Honestly though switching to Radium after this is implemented on their end would be the best move imo.
FormidableLabs/radium#374

@TheUltDev
Copy link
Contributor

I've submitted a PR that might be a suitable solution for most #2007.

@oliviertassinari
Copy link
Member

@Cavitt Thanks. The prefix variation between server/client side should be fixed. Please refer to #2077 for the LeftNav component.

@vvinton
Copy link

vvinton commented Sep 21, 2016

Was that issue fixed? Have anyone verified it? I'm using material 0.15.3 and react 15.3.0 and getting:
different on the client or server:
(client) ght:24px;width:24px;transition:all 450ms
(server) ght:24px;width:24px;user-select:none;tra

All is related to:
<svg style="display:inline-block;color:#ffffff;fill:#ffffff;height:24px;width:24px;user-select:none;transition:all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;mui-prepared:;" viewBox="0 0 24 24" data-reactid="6"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" data-reactid="7"></path></svg>
Vs.
<svg style="display:inline-block;color:#ffffff;fill:#ffffff;height:24px;width:24px;transition:all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;mui-prepared:;-webkit-user-select:none;" viewBox="0 0 24 24" data-reactid="6"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" data-reactid="7"></path></svg>

@zannager zannager added the package: styles Specific to @mui/styles. Legacy package, @material-ui/styled-engine is taking over in v5. label Dec 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package: styles Specific to @mui/styles. Legacy package, @material-ui/styled-engine is taking over in v5.
Projects
None yet
Development

No branches or pull requests