emotion-js / emotion

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

esbuild plugin #2891

Open ryancrunchi opened 1 year ago

ryancrunchi commented 1 year ago

The problem I'm trying to use @craco/craco with craco-esbuild plugin to build my React app. I use @emotion with MUI in this react app with some component selectors in my styled components. Problem is when I build with craco-esbuild, I get error Component selectors can only be used in conjunction with @emotion/babel-plugin, the swc Emotion plugin, or another Emotion-aware compiler transform

Proposed solution Have an esbuild plugin for emotion, the same way we have @emotion/babel-plugin

Alternative solutions

Additional context

cbilotta commented 1 year ago

Hello,

I think this would be very useful as without a plugin, if I'm not misguided, it's not possible to get sourceMaps for CSS generated by emotion to work correctly.

I wanted to migrate from Webpack to Vite but without sourceMaps support, it's pretty much a dealbreaker on big projects.

I decided to explore Parcel in the meantime, but I suppose it might be affecting a few people and might be interesting to dig into.

Andarist commented 1 year ago

Unfortunately, esbuild's plugin system is pretty limited: https://esbuild.github.io/plugins/#plugin-api-limitations . Our Babel plugin manipulates the AST and while maybe you could get some positive results with regexps... I don't intend to write and maintain any. Code transformations should be done with AST to ensure the maximum possible correctness. An alternative would be to write an esbuild plugin that... would invoke Babel (or something else), but that's pretty counter-productive. That being said - such a plugin could be scoped to some specific files etc so the performance hit could be restrained a little bit.

cbilotta commented 1 year ago

Thank you for your fast reply,

Makes perfect sense, thank you for your explanation. Would indeed defeat the purpose of having a fast/reliable build tool.

Seems like I'll have to go for another build tool ☺️

Ethorsen commented 1 year ago

Such a plugin would be amazing. In the meantime, moving an existing project to Vite seems impossible

ndelangen commented 1 year ago

@Andarist is there some reason why this problem would only happen in dev-mode and not in prod mode?

Andarist commented 1 year ago

@ndelangen could you elaborate? I'm not sure what you refer to as "this problem" here.

ndelangen commented 1 year ago

Sorry, of course!

With "this problem" I mean the error "Component selectors can only be used in conjunction with @emotion/babel-plugin, the swc Emotion plugin, or another Emotion-aware compiler transform" being thrown at runtime; after the code has been bundled by esbuild.

Storybook uses esbuild to bundle manager entries (parts of addons that are renderered inside of storybook's manager UI.

It seems that if emotion is used (with component-selectors) inside it break. Which is expected honestly.

But strangely enough... it seems to work fine when we do a build-storybook.. which still uses esbuild, in fact the only difference would be https://github.com/storybookjs/storybook/blob/28789f04ba5c0664fa14f7d9355b689528a8cbc6/code/lib/builder-manager/src/index.ts#L229

But we also "provide" process.env, like so: https://github.com/storybookjs/storybook/blob/28789f04ba5c0664fa14f7d9355b689528a8cbc6/code/lib/builder-manager/src/index.ts#L97-L102

it seems that somehow the code generated then is different, and doesn't throw the error.. My question is if you'd have any idea why it would work in this case, or rather... why the error isn't thrown?

Andarist commented 1 year ago

Perhaps you replace process.env.NODE_ENV with 'production' there? https://github.com/emotion-js/emotion/blob/314a5fb08b0f730e7aa88da0c974dfea13cc9b32/packages/styled/src/base.js#L189-L200

LPGhatguy commented 1 year ago

We are running into this issue after migrating from styled-components to @emotion/styled. styled-components doesn't appear to have this limitation, what are they doing differently to support this feature without a plugin?