ben-rogerson / twin.macro

๐Ÿฆนโ€โ™‚๏ธ Twin blends the magic of Tailwind with the flexibility of css-in-js (emotion, styled-components, solid-styled-components, stitches and goober) at build time.
MIT License
7.92k stars 183 forks source link

ReferenceError: styled is not defined #192

Closed bebbi closed 2 years ago

bebbi commented 3 years ago

In an otherwise well-working project with gatsby + styled-components (using tw prop, css prop, and tw import is working fine), I randomly can't get the styled import to work and get ReferenceError: styled is not defined if I try.

The error doesn't come up always. First I've managed to get it to work somehow. After that, I could get it to fail again with above error by:

Sorry I can't pin it down more precisely.

The setup: gatsby 2.26.1, styled-components 5.2.1, twin.macro 1.12.1. (But playing with some earlier twin version didn't appear to change the behaviour). Running in a yarn workspaces setting if that matters.

package.json:

  "babelMacros": {
    "twin": {
      "preset": "styled-components",
      "config": "src/tailwind.config.js",
      "autoCssProp": true,
      "debugProp": true,
      "debugPlugins": false,
      "debug": false
    }
  },

I've tried replacing the preset with

      "styled": {
        "import": "default",
        "from": "styled-components"
      },
      "css": {
        "import": "css",
        "from": "styled-components/macro"
      },
      "global": {
        "import": "createGlobalStyle",
        "from": "styled-components"
      }

but that didn't change the outcome.

Btw: I love the twin project, your pace of adding new goodies is addictive..

ben-rogerson commented 3 years ago

Hey there, thanks for bringing up this issue and posting this detailed report.

This reminds me of a styled bug I've also been trying to pinpoint, maybe it's the same one!

It seems to manifest when you use a mixture of the css/tw props and the styled import but I'm having trouble tracking it down again also.

What I think might be happening is that Babel usually renames styled to _styled to avoid conflicting with user imports. Then sometime after that, the styled import tries to get used and isn't found.

I'll circle back to this after the next twin release is out, then maybe we can crack the case on this one :)

bebbi commented 3 years ago

Barring unforeseen codebase changes, I should be able to reproduce this anytime. Happy to assist when you're ready!

ben-rogerson commented 3 years ago

Hey @bebbi, let's do this ๐Ÿ˜ƒ

bebbi commented 3 years ago

I can still repro this. You have the lead :)

ben-rogerson commented 3 years ago

sounds like you're able to pinpoint it now, you could either post the steps here or jump into our discord to discuss ๐Ÿ‘

denu5 commented 3 years ago

1+ on this issue. also in a nextjs setup. will investigate my setup

Module '"../../../node_modules/twin.macro/types"' has no exported member 'styled'. Did you mean to use 'import styled from "../../../node_modules/twin.macro/types"' instead?


import tw, { css, styled, theme } from 'twin.macro'

interface ButtonProps {
  isPrimary?: boolean
  isSecondary?: boolean
  isSmall?: boolean
}

const Button = styled.button(
  ({ isPrimary, isSecondary, isSmall }: ButtonProps) => [
    // The common button styles
    tw`text-lg px-8 py-2 rounded focus:outline-none`,
    tw`transform transition-transform duration-75`,

    // Use the variant grouping feature to add variants to multiple classes
    tw`hocus:(scale-105 text-yellow-400)`,

    // Use props to conditionally style your components
    isPrimary && tw`bg-black text-white border-black`,

    // Combine regular css with tailwind classes within backticks
    isSecondary && [
      css`
        box-shadow: 0 0.1em 0 0 rgba(0, 0, 0, 0.25);
      `,
      tw`border-2 border-yellow-600`,
    ],

    // Conditional props can be added
    isSmall ? tw`text-sm` : tw`text-lg`,

    // The theme import can supply values from your tailwind.config.js
    css`
      color: ${theme`colors.white`};
    `,
  ],
)

export default Button
ben-rogerson commented 3 years ago

@denu5 I think you might have a separate issue there. Check you have typescript setup and make sure @types/react is installed (I need to add this step to the docs as it's a new requirement).


The issue above is due to a custom twin import config that no longer works - it's triggered when the styled import isn't imported from styled-components/macro, like this:

// package.json
  "babelMacros": {
    "twin": {
      "styled": {
        "import": "default",
        "from": "styled-components"
      },
      "css": {
        "import": "css",
        "from": "styled-components/macro"
      },
      "global": {
        "import": "createGlobalStyle",
        "from": "styled-components"
      }
    }
  },

The new preset does this for you, so the config should be changed to this:

// package.json
  "babelMacros": {
    "twin": {
      "preset": "styled-components"
    }
  },
denu5 commented 3 years ago

Hi @ben-rogerson - my bad, I naively copied the button.tsx without reading the docs about the ts config. works! @types/react was already installed. moving on with tw now, wohoo! ๐Ÿ‘ : Thanks a lot for the quick answer.

ben-rogerson commented 3 years ago

This should be fixed with the new import presets now, feel free to reopen if it's still an issue ๐Ÿ‘

najathi commented 2 years ago

I fixed this error, try this

babel-plugin-macros.config.js

  twin: {
    styled: "styled-components",
    config: "./tailwind.config.js",
    format: "auto"
  }
};

OR

package.json

"babelMacros": {
    "twin": {
      "styled": "styled-components",
      "config": "./tailwind.config.js",
      "format": "auto"
    }
  }
ben-rogerson commented 2 years ago

Twin doesn't have an item called format in it's config. Try this config and see if it still fixes your issue @najathi:

"babelMacros": {
    "twin": {
      "preset": "styled-components",
    }
  }
najathi commented 2 years ago

yeah, it works @ben-rogerson. Thanks

qscacheri commented 2 years ago

I'm still getting this error (following the vite example). It seems to happen whenever use the tw prop. Any help would be greatly appreciated.

ben-rogerson commented 2 years ago

@qscacheri I just tested both of the vite examples (emotion / styled-components) out with a fresh yarn install, which use the tw prop with no issues. You could compare your setup with one of those examples or drop a link to a repo so I can take a look?

qscacheri commented 2 years ago

Seems like it could be user error, but I cloned the styled-components example, and only modified App.tsx to be the following and I am still getting the error.

import React from 'react'
import { Logo } from './components'
import tw, { styled, TwStyle } from 'twin.macro'

type ButtonVariant = 'green' | 'blue' | 'red' | 'gray'

interface ButtonProps {
  variant?: ButtonVariant
}

const buttonVariants: Record<ButtonVariant, TwStyle> = {
  blue: tw`bg-blue-400 focus:ring-blue-400 hover:bg-blue-500 disabled:bg-blue-400`,
  green: tw`bg-green-400 focus:ring-green-400 hover:bg-green-500 disabled:bg-green-400`,
  red: tw`bg-red-400 focus:ring-red-400 hover:bg-red-500 disabled:bg-red-400`,
  gray: tw`text-black bg-gray-200 focus:ring-gray-200 hover:bg-gray-300 disabled:bg-gray-200`,
}

export const Button = styled.button<ButtonProps>(() => [
  tw`h-10 px-4 py-2 mx-2 my-auto text-sm text-white transition-all rounded-lg focus:outline-none focus:ring-2 focus:ring-opacity-75 disabled:opacity-50 disabled:cursor-default`,

  ({ variant = 'blue' }) => buttonVariants[variant],
])

const App = () => (
  <div>
    <div tw="flex flex-col justify-center h-full gap-y-5"></div>
    <Button variant="blue" tw="bg-red-500">
      Click me
    </Button>
  </div>
)

export default App
ben-rogerson commented 2 years ago

@qscacheri Which example did you use - so I can look into this?

qscacheri commented 2 years ago

This one:

https://github.com/ben-rogerson/twin.examples/vite-styled-components-typescript

ben-rogerson commented 2 years ago

I see the issue mentioned, let me look into this.

ben-rogerson commented 2 years ago

_styled is not defined

I've taken a look into this error and found that it happens when we add a tw prop on a styled component using the styled-components library, eg:

import tw from "twin.macro";
const Test = tw.div`mt-5`;
<Test tw="block" />;

The styled-components preset defined a default styled import of import styled from "styled-components/macro. The problem is that their macro doesn't preserve the _styled import twin.macro adds for the tw prop. To avoid this, the solution is to switch to the non-macro import import styled from "styled-components.


Edit: twin.macro@2.8.2 fixed the error by updating the preset to use the updated import. In the same version twin had to remove the css prop feature and now it should be added by babel-plugin-styled-components.

Hereโ€™s the minimum config youโ€™ll now need:

// package.json
"babelMacros": {
    "twin": {
      "preset": "styled-components"
    }
},
ben-rogerson commented 2 years ago

I've now added a patch for the _styled is not defined error in twin.macro@2.8.2 ๐ŸŽ‰

qscacheri commented 2 years ago

Awesome thanks!

mszmida commented 2 years ago

@ben-rogerson The problem still occurs in a quite peculiar case when the styled import is used together with this syntax:

const Component = tw['p']`text-base`

Take a look on this React component:

import { ElementType, PropsWithChildren, ComponentPropsWithoutRef, ReactElement } from 'react'
import tw, { styled } from 'twin.macro'

const Container = styled.div(() => [
  // some tyles here
])

export type TextProps<T extends ElementType> = PropsWithChildren<{
  as?: T
}>

export default function Text<T extends ElementType = 'p'>({
  as,
  children,
  ...rest
}: TextProps<T> & Omit<ComponentPropsWithoutRef<T>, keyof TextProps<T>>): ReactElement {
  // WARNING!: This is the problematic syntax:
  const Component = tw[(as || 'p') as string]`text-base`

  return <Component {...rest}>{children}</Component>
}

The returned error visible below:

image

points to the problematic line from the component source code above:

const Component = tw[(as || 'p') as string]`text-base`

However this syntax is processed correctly and runs without errors:

const Component = tw.p`text-base`

Dependencies:

A workaround I came up with for this problem is to manually save lost reference to the styled import in the local variable called styledRef and create a styled element using that variable:

import { ElementType, PropsWithChildren, ComponentPropsWithoutRef, ReactElement } from 'react'
import tw, { styled } from 'twin.macro'

// Reference is preserved in the local variable during bundle processing:
const styledRef = styled

const Container = styledRef.div(() => [
  // some tyles here
])

// ...
// rest of the component code remains unchanged

I hope that my solution help to find the root cause and unblock the community while waiting for the fix.

@ben-rogerson I appreciate all the work you have done to create this macro. Thank you! ๐Ÿ‘

ben-rogerson commented 2 years ago

@mszmida Twin 's tw function can't support a dynamic as due to babel limitations, but using styled will work:

import tw, { styled } from 'twin.macro'
const as = 'dialog'
const Component = styled(as)(() => [tw`text-base`])
ratneshmurugesan commented 1 year ago

This should help

https://github.com/ben-rogerson/twin.examples/tree/master/next-styled-components-typescript#add-typescript-types

declare module "twin.macro" {
  // The styled and css imports
  const styled: typeof styledImport;
  const css: typeof cssImport;
}