Next.js: Fails to Compile styled-components that use Props

Created on 9 Oct 2017  路  20Comments  路  Source: vercel/next.js

  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

I had a simple working styled-components header inside a Next@3 website:

h1 {
    cursor: pointer;
    ${props => (props.primary && 'font-size: 6rem;') || 'font-size: 2rem;'}
    line-height: 1.1;
    margin-bottom: 1rem;
    transform: skewY(-2deg);
  }

This is based on the documentation for styled-components at: https://www.styled-components.com/docs/basics#adapting-based-on-props

Current Behavior

Upgrading to next@4 resulted in the following error message:

Module build failed: SyntaxError: 
      Found an `undefined` or invalid value in your styles: `props.primary`.

      If you are trying to use dynamic styles in external files this is unfortunately not possible yet.
      Please put the dynamic parts alongside the component. E.g.

      <button>
        <style jsx>{externalStylesReference}</style>
        <style jsx>{`
          button { background-color: ${props.primary} }
        `}</style>
      </button>

Steps to Reproduce (for bugs)

  1. Init a new Next@3 site with styled-components@latest, sample document, page and component: https://gist.github.com/jamiemchale/3d7d593f7911ad33b354a80f134b32fd
  2. Run, see site.
  3. Update to Next@4, run, see error.

Most helpful comment

This issue should be fixed in ^4.0.2

All 20 comments

Have you tried adding a semicolon here: 'font-size: 2rem;'}; <--? You can also let prettier do that for you automatically in the future, I can recommend that together with this extension: https://marketplace.visualstudio.com/items?itemName=jpoissonnier.vscode-styled-components

Didn't have an effect, same error observed.

The following works for me using next 4

import Aux from 'react-aux';
import styled from 'styled-components';

const Comp = styled.h1`
  cursor: pointer;
  ${({ primary }) => (primary ? 'font-size: 6rem' : 'font-size: 2rem')};
  line-height: 1.1;
  margin-bottom: 1rem;
  transform: skewY(-2deg);
`;

export default () => (
  <Aux>
    <Comp>a</Comp>
    <Comp primary>a</Comp>
  </Aux>
);

https://www.dropbox.com/s/c0k36b5gblqtbiq/Screenshot%202017-10-09%2021.49.01.png?dl=0

@linus-gubenis thanks for looking into this - your code is giving me an error:

Invalid tag: {cursor:pointer;function (_ref) { var primary = _ref.primary; return primary ? 'font-size: 6rem' : 'font-size: 2rem'; };line-height:1.1;margin-bottom:1rem;-webkit-transform:skewy(-2deg);-ms-transform:skewy(-2deg);transform:skewy(-2deg)} /*# sourcemappingurl=data:application/json;base64,eyj2zxjzaw9uijozlcjzb3vyy2vzijpbinbhz2vzl2luzgv4lmpzp2vudhj5il0sim5hbwvzijpbxswibwfwcgluz3mioijbquvzqixbquvrqixlqunhldzcqunalgdcqunhlg1cqunjlglgqun6qiisimzpbguioijwywdlcy9pbmrlec5qcz9lbnryesisinnvdxjjzvjvb3qioiivvxnlcnmvamftawvty2hhbguvrgvza3rvcc90zxn0bmv4dcisinnvdxjjzxndb250zw50ijpbimltcg9ydcbzdhlszwqgznjvbsanc3r5bgvklwnvbxbvbmvudhmno1xuxg5jb25zdcbdb21wid0gc3r5bgvklmgxyfxuicbjdxjzb3i6ihbvaw50zxi7xg4gicr7khsgchjpbwfyesb9ksa9piaochjpbwfyesa/icdmb250lxnpemu6idzyzw0nidogj2zvbnqtc2l6ztogmnjlbscpfttcbiagbgluzs1ozwlnahq6ideumttcbiagbwfyz2lulwjvdhrvbtogmxjlbttcbiagdhjhbnnmb3jtoibza2v3wsgtmmrlzyk7xg5go1xuxg5lehbvcnqgzgvmyxvsdcaoksa9piaoxg4gidxkaxy+xg4gicagpenvbxa+ytwvq29tcd5cbiagica8q29tccbwcmltyxj5pme8l0nvbxa+xg4gidwvzgl2plxukttcbijdfq== */ /*@ sourceurl=pages/index.js?entry */

I've scrubbed my node_modules to be sure of this. Does it work without the destructuring in the Comp?

No worries @jamiemchale, can you provide the exact portion of your code (including the component), for me to try and reproduce? And maybe the versions of the modules in play, I'm using react 16, next 4 and styled-components 2.2.1 maybe it's just some syntax error.

edit: Yes, it works without destructuring as well:

import Aux from 'react-aux';
import styled from 'styled-components';

const Comp = styled.h1`
  cursor: pointer;
  ${(props) => (props.primary ? 'font-size: 6rem' : 'font-size: 2rem')};
  line-height: 1.1;
  margin-bottom: 1rem;
  transform: skewY(-2deg);
`;

export default () => (
  <Aux>
    <Comp>a</Comp>
    <Comp primary>a</Comp>
  </Aux>
);

Dependencies:

    "next": "^4.0.0",
    "react": "^16.0.0",
    "react-dom": "^16.0.0",
    "styled-components": "^2.2.1"

/pages/_document.js as per with-styled-components example: https://raw.githubusercontent.com/zeit/next.js/master/examples/with-styled-components/pages/_document.js

My component pages/index.js

import styled from 'styled-components';

const Header = styled.div`
  background: #004DBA;
  color: #fff;

  h1 {
    ${({ primary }) => primary ? 'font-size: 6rem;' : 'font-size: 2rem;'}
  }
`;


export default () => (
  <div>
    <Header primary>
      <h1>Test Page</h1>
    </Header>
    <p>Lorem.</p>
  </div>
)

When the props are destructured I get the invalid tag error, when it is not destructured I get the original syntax error.

Do you have _document.js set up as per the styled-components example?

my _document.js looks like the following, it does a bit more even than in the styled-components example, because I'm using it together with material-ui.

import Document, { Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';
import JssProvider from 'react-jss/lib/JssProvider';

import getContext from 'utils/getContext';

class _Document extends Document {
  render() {
    return (
      <html lang="en" dir="ltr">
        <Head>
          <title>next-mui-sc-mobx</title>

          <meta charSet="utf-8" />

          <link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png" />
          <link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png" />
          <link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png" />
          <link rel="shortcut icon" href="/static/favicon.ico" />
          <meta name="msapplication-config" content="/static/browserconfig.xml" />
          <meta name="theme-color" content="#ffffff" />

          <meta
            name="viewport"
            content="user-scalable=0, initial-scale=1, minimum-scale=1, width=device-width"
          />
          <link rel="manifest" href="/static/manifest.json" />
          {this.props.styleTags}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </html>
    );
  }
}

/**
 * This will only run once, on the serverside before the _Document above is being rendered
 */
_Document.getInitialProps = ({ renderPage }) => {
  const sheet = new ServerStyleSheet();

  const context = getContext();

  const page = renderPage(App => props =>
    sheet.collectStyles(
      <JssProvider registry={context.sheetsRegistry} jss={context.jss}>
        <App {...props} />
      </JssProvider>,
    ),
  );

  const styleTags = sheet.getStyleElement();

  const styles = (
    <style
      id="jss-server-side"
      dangerouslySetInnerHTML={{
        __html: `${context.sheetsRegistry.toString()}\n`,
      }}
    />
  );

  return {
    ...page,
    styleTags,
    stylesContext: context,
    styles,
  };
};

export default _Document;

Your example rendered without any errors as following: https://www.dropbox.com/s/q3n4gzqyb61gfqc/Screenshot%202017-10-09%2022.58.37.png?dl=0
when written like this:

import styled from 'styled-components';

const Header = styled.div`
  background: #004dba;
  color: #fff;

  h1 {
    ${({ primary }) => (primary ? 'font-size: 6rem' : 'font-size: 2rem')};
  }
`;

export default () => (
  <div>
    <Header primary>
      <h1>Test Page</h1>
    </Header>
    <p>Lorem.</p>
  </div>
);

Still getting the issues mentioned above. Reinstalled all the node_modules, and scrubbed the next build directory. Will dig into this more tomorrow, unless anyone else is able to reproduce and provide further thoughts.

This is what I used to run your example: https://github.com/componentDidMount/next-material-ui-styled-components-mobx just clone it, run yarn, replace the components/Navigation.js files content with your example and run npm run watch, visit http://localhost:5000 > et voila, maybe that works.

So it'd be good to figure out what the source of the error is, so that the styled-components or next documentation can be updated. I'll pull down your example and then try to figure out the differences. Thanks for your help!

Yes, would be interesting to know whats happening there, I cannot explain it myself, take care.

I'm getting the same error after updating to Next.js 4. Haven't figured out the cause yet.

Same here! In addition to that I am also seeing:

Module build failed: TypeError: Property body[1] of BlockStatement expected node to be of a type ["Statement"] but instead got "CallExpression"

Could be related?

Thats really weird, I got no issues at all after updating to next4 + styled-components but I don't use styled-jsx anywhere, are any of you guys?

@componentDidMount no jsx anywhere. but next still tells me that I am using it the wrong way -.-

Btw I've had the same problem after updating, but strangely enough only with the SomeStyledComponent.extend`` syntax. For now I'm just working around that, but feels a little iffy, need to investigate more.

I'm running into the same issue as @hyperborea. From a quick look, it seems like the styled-jsx babel plugin is picking up the extend syntax and thinking it's styled-jsx, so it's seeing the props in that block and throwing the error. Removing the use of extend removed the error for now.

This issue should be fixed in ^4.0.2

@componentDidMount JFYI your username is funny, although it breaks search for the relevant issues

Was this page helpful?
0 / 5 - 0 ratings