styled-components / stylis-plugin-rtl

↔️ stylis RTL plugin based on CSSJanus
MIT License
37 stars 18 forks source link

Implementation in SSR (Next.js) #5

Open sanishkr opened 4 years ago

sanishkr commented 4 years ago

Where do I implement in SSR (Next.js)? Should I keep StyleSheetManager in _app.js or in _document.js? I think it should be in _document.js. But I tried wrapping my in StyleSheetManager, it doesn't work.

Here is a sample _document.js without this plugin.

import Document, { Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';
import stylisRTLPlugin from 'stylis-plugin-rtl';
import { parseCookies } from 'nookies';

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;
    const { html, head, errorHtml, chunks } = ctx.renderPage();
    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: App => props => sheet.collectStyles(<App {...props} />)
        });
      const initialProps = await Document.getInitialProps(ctx);
      const cookies = parseCookies(ctx);
      initialProps.language = cookies['next-i18next'] || 'en';
      initialProps.direction = initialProps.language === 'ar' ? 'rtl' : 'ltr';
      return {
        html,
        head,
        errorHtml,
        chunks,
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        )
      };
    } finally {
      sheet.seal();
    }
  }
  render() {
    const { language, direction } = this.props;
    return (
      <html dir={direction} lang={language}>
        <body>
          {this.props.customValue}
          <Main />
          <NextScript />
        </body>
      </html>
    );
  }
}

Here is what I tried

.
.
.
       <StyleSheetManager
          stylisPlugins={language === 'ar' ? [stylisRTLPlugin] : []}
        >
          <body>
            {this.props.customValue}
            <Main />
            <NextScript />
          </body>
        </StyleSheetManager>
.
.
.
Migggz commented 4 years ago

It should be in _app.js

<StyleSheetManager stylisPlugins={language === "ar" ? [stylisRTLPlugin] : []}>
   {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
   <CssBaseline />
   <Page {...pageProps}  />
</StyleSheetManager>
sanishkr commented 4 years ago

Thanks, @Migggz for the suggestion. I had tried like this in _app.js:

.
.
.
         {language ? (
            <StyleSheetManager
              stylisPlugins={language === 'ar' ? [stylisRTLPlugin] : []}
            >
              <Component {...pageProps} />
            </StyleSheetManager>
          ) : null}
.
.

Conditional to do re-rendering when I hit change language. It wasn't working otherwise. What is CssBaseline though?

oliviertassinari commented 4 years ago

What is CssBaseline though?

@sanishkr https://material-ui.com/components/css-baseline/

sanishkr commented 4 years ago

Got it. Thanks @oliviertassinari

Can anyone help me why it doesn't work when doing like this:

    <StyleSheetManager
              stylisPlugins={language === 'ar' ? [stylisRTLPlugin] : []}
            >
              <Component {...pageProps} />
    </StyleSheetManager>

I have to do like this:

         {language ? (
            <StyleSheetManager
              stylisPlugins={language === 'ar' ? [stylisRTLPlugin] : []}
            >
              <Component {...pageProps} />
            </StyleSheetManager>
          ) : null}

But this approach has its own problems. I have made an example here to look at. Check components/Theme.js. Just comment line 17 and 23.

CodeSandbox

barghi commented 4 years ago

@sanishkr Have you found a solution?

sanishkr commented 4 years ago

Nope. It's a really cool plugin but authors or community doesn't have much support yet.

barghi commented 4 years ago

everything is ok in development mode, when I run the project in production mode, RTL-plugin won't work at first render and if I navigate to another page (in the client) styles will show without any problem

the problem is: server render in production mode:

here is _app.js file:

render() {
 const { Component, pageProps, store, lang } = this.props;
 const stylePlugins = [];

 if (APP_CONSTANTS.LANG[lang].direction === 'rtl') {
   stylePlugins.push(rtlPlugin);
 }

 return (
   <Provider store={store}>
      <ThemeProvider theme={theme}>
         <StyleSheetManager stylisPlugins={stylePlugins}>
            <Component {...pageProps} />
         </StyleSheetManager>
      </ThemeProvider>
   </Provider>
 );
}
sanishkr commented 4 years ago

Looks fine. A repo would be useful.

Or check this sandbox

Stewiey commented 4 years ago

any news on this bug ? StyleSheetManager/stylisRTLPlugin doesn't seem to work at all with nextjs, i followed the guide in styled-components about how to implement in nextjs.

<StyleSheetManager stylisPlugins={[stylisRTLPlugin]}>

the css doesn't flip