cssinjs / jss

JSS is an authoring tool for CSS which uses JavaScript as a host language.
https://cssinjs.org
MIT License
7.08k stars 400 forks source link

Error with multiple same component child #1492

Open Yomyer opened 3 years ago

Yomyer commented 3 years ago

Expected behavior: It should not display such a warning

Describe the bug: I get the warning: Warning: [JSS] Rule is not linked. Missing sheet option "link: true". when I duplicate in a component the same child component when it has a dynamic value. I am using Next SSR and have already reported the problem but I don't know where the problem is coming from.

https://github.com/vercel/next.js/issues/23872

If it only appears once it does not show the warning

Thanks ;)

Reproduction: Install the example with-react-jss-app

npx create-next-app --example with-react-jss with-react-jss-app Then modify the pages/index.js to

import { createUseStyles } from 'react-jss'
const useStyes = createUseStyles({
  header: {
    color: props => props.color
  }
})

const Bar = () => {
  const classes = useStyes({ color: 'green' });

  return (
    <>
      <h2 className={classes.header}>dasdasda</h2>
    </>
  )
}

function Index() {
  return (
    <div>
      <h1>
        Example on how to use react-jss with Next.js
      </h1>
      <Bar></Bar>
      <Bar></Bar>
    </div>
  )
}

export default Index

Run in dev mode

npm run dev o yarn dev And it will show the warning:

Warning: [JSS] Rule is not linked. Missing sheet option "link: true".

Versions (please complete the following information):

kof commented 3 years ago

The logic which shows this error must be thinking code is running on the client. Something is wrong with the detection mechanism. Feel free to debug.

rtivital commented 3 years ago

@kof Can you point me to the place where detection mechanism is located?

My current observation is that this happens exclusively with Next.js (I've tested the same components with Gatsby and custom server, all of them do not show the warning)

I guess the dumbest solution will be to replace this with:

if (typeof window !== 'undefined' && sheet && sheet.attached) {
  warning(false, '[JSS] Rule is not linked. Missing sheet option "link: true".')
}
kof commented 3 years ago

Not sure, from a quick look it should be broken for all platforms, because they will be getting to this warning because there is no renderable on the server and the still has sheet.attached===true and you get there most likely from react-jss updateDynamicRules() then jss sheet.updateOne().

I don't see from reading the jss code why this would only happen on next and not on gatsby. Only if gatsby has dom api exposed serverside too.

kof commented 3 years ago

I am thinking that sheet.attached there assumed it can only be true when on the client but ages ago we changed that so that sheet can be attached serverside but do nothing in dom renderer.

kof commented 3 years ago

In theory the missing piece is that .renderer should be null serverside in style rule, so react-jss should be passing Renderer: null to jss.createStyleSheet({Renderer: null}) when serverside and in addition to that we should if (this.renderer === null) return this here

We also need a test in react-jss for this and ideally we need to understand how this is not happening for everybody, but only in next, it seems to me it should be broken for everybody when styles with function values are used in react-jss.

rtivital commented 3 years ago

@kof I've managed to replicate this issue with regular ssr server (not Next), here what I did:

  getDataFromTree(_App).then(() => {
    const initialState = client.extract();

    const registry = new SheetsRegistry();

    const c = renderToString(
      <JssProvider registry={registry} generateId={createGenerateId()}>
        {_App}
      </JssProvider>
    );

    const html = renderToStaticMarkup(
      <Html
        helmetContext={helmetContext}
        scripts={[res.locals.assetPath('bundle.js'), res.locals.assetPath('vendor.js')]}
        styles={registry.toString()}
        apolloState={initialState}
      >
        {c}
      </Html>
    );

    res.status(200);
    res.send(`<!doctype html>\n${html}`);
  });

And then in console

Снимок экрана 2021-08-17 в 12 53 05