emotion-js / emotion

👩‍🎤 CSS-in-JS library designed for high performance style composition
https://emotion.sh/
MIT License
17.43k stars 1.11k forks source link

Component selectors can only be used in conjunction with @emotion/babel-plugin #2421

Closed ZenWhite closed 3 years ago

ZenWhite commented 3 years ago

Hello. I am using Next.js and due to some strange SSR bugs I migrated from styled-components to @emotion/styled, hoping there was no problem.

But now I am facing a strange error:

image

Moreover, this error pops up only in dev-mode, everything is assembled in prod, but my checkboxes (code below) still do not want to work

Dependencies

{
  "name": "carpets",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "dev": "next dev",
    "start": "next start",
    "build": "next build",
    "format": "prettier -w src/**/*.{js,jsx} --config ./.prettierrc"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@emotion/babel-plugin": "^11.3.0",
    "@emotion/react": "^11.4.0",
    "@emotion/styled": "^11.3.0",
    "@svgr/webpack": "~5.5.0",
    "camelcase-keys": "^6.2.2",
    "dotenv": "~10.0.0",
    "form-data": "~4.0.0",
    "next": "^11.0.1",
    "preact": "^10.5.13",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-html-parser": "^2.0.2",
    "react-slick": "^0.28.1",
    "react-toastify": "~7.0.4",
    "traverse": "^0.6.6"
  },
  "devDependencies": {
    "prettier": "^2.3.2"
  }
}

Next js config

module.exports = {
  webpack: (config, { webpack, dev, isServer }) => {
    const rules = [{ test: /\.svg$/, use: ['@svgr/webpack'] }]

    const plugins = [
      new webpack.ProvidePlugin({ styled: ['@emotion/styled', 'default'] })
    ]

    config.module.rules.push(...rules)

    config.plugins.push(...plugins)

    if (!dev && !isServer) {
      Object.assign(config.resolve.alias, {
        react: 'preact/compat',
        'react-dom/test-utils': 'preact/test-utils',
        'react-dom': 'preact/compat'
      })
    }

    return config
  },

  env: {
    WP_AUTH: process.env.WP_AUTH,
    USER_KEY: process.env.USER_KEY,
    USER_SECRET_CODE: process.env.USER_SECRET_CODE,
    BASE_URL: process.env.BASE_URL,
    EMBEDDED_KEY: process.env.EMBEDDED_KEY
  }
}

Babel

{
  "presets": ["next/babel"],

  "plugins": ["@emotion"]
}

Component

import { Icon } from 'components/Icon/icon.component'

import { Wrapper, Label, Input, Span } from './item.styled'

export const Item = ({ id, name, type, label, action, slug, active }) => {
  return (
    <Wrapper>
      <Input
        type="checkbox"
        name={name}
        id={id}
        checked={active}
        onChange={({ target }) =>
          action((state) => ({
            ...state,
            [type]: target.checked
              ? [...state[type], { slug, id }]
              : state[type].filter((item) => item.id != id)
          }))
        }
      />

      <Label htmlFor={id}>
        <Span>{label}</Span>

        <Icon type="check" width={12} height={12} />
      </Label>

      {type == 'pa_country' && <Icon type={slug} width={28} height={28} />}
    </Wrapper>
  )
}

Component styles

export const Wrapper = styled.div`
  position: relative;

  display: flex;
  align-items: center;
  gap: 12px;
`

export const Label = styled.label`
  width: fit-content;

  user-select: none;

  display: flex;
  align-items: center;
  gap: 12px;

  cursor: pointer;

  text-transform: capitalize;

  ::before {
    content: '';

    width: 36px;
    height: 36px;

    display: block;

    background: transparent;

    border: 1px solid ${(p) => p.theme.color.yellow};

    border-radius: 5px;

    transition-property: opacity;
    transition-duration: 500ms;
  }

  :hover:before {
    opacity: 0.8;
  }

  svg {
    position: absolute;
    left: 12px;
    fill: transparent;
  }
`

export const Input = styled.input`
  opacity: 0;

  position: absolute;

  &:checked + ${Label}::before {
    background: ${(p) => p.theme.color.yellow};
  }

  &:checked + ${Label} {
    svg {
      fill: ${(p) => p.theme.color.white};
    }
  }

  &:focus + ${Label}::before {
    border: 1px solid ${(p) => p.theme.color.dark};
  }
`

export const Span = styled.span``
techdiary commented 3 years ago

@ZenWhite I'm facing similar issue, what was the resolution for above. can you please explain