Open trappar opened 1 year ago
@trappar Hey man, just had a look for ya and it seems like you both had none of the emotion plugins installed and/or configured + a not working syntax in your home page which together prevented the text to become green as you explained
see example here: https://github.com/JesseKoldewijn/nextjs-emotion-example
The incorrect syntax was the [ ] around your inner A tag on the B styled component.
Funny enough you do have these brackets around your A in the B element on your codesandbox but not in the snippet shown in your issue.
There is still something fishy going on.
The brackets were just an artifact of me playing around trying to get it to work, which is why they weren't present in the example I gave. I removed them and it still failed.
As far as I can tell from the documentation, NextJS has built in support for emotion without installing that swc plugin. Also, I didn't enable emotion in the compiler options because the documentation claims that it's enabled by default, at least when running in dev (which is very confusing btw):
module.exports = {
compiler: {
emotion: boolean | {
// default is true. It will be disabled when build type is production.
I can confirm that emotion is working without setting emotion: true
. See this codesandbox for an example of this: https://codesandbox.io/p/sandbox/throbbing-cdn-oip9jv
Now what's really strange is that if I do set emotion: true
in my next.config.js
, then this particular feature suddenly starts working. This works even without installing @swc/plugin-emotion.
I've updated my original codesandbox to this state (emotion enabled in next config and no extra plugin installed). See here: https://codesandbox.io/p/sandbox/polished-browser-went6z
So maybe the issue is that the documentation claims that emotion is enabled by default, which it sort of is... but in some half-functional state where not all features work?
Definitely still seems like there are some improvements needed.
Also, I didn't enable emotion in the compiler options because the documentation claims that it's enabled by default, at least when running in dev (which is very confusing btw):
I believe the "default is true" comment is referring to the sourceMap
setting:
// default is true. It will be disabled when build type is production.
sourceMap?: boolean,
If compiler.emotion
is not set in the next.config.js
, then the Emotion plugin will not be enabled:
https://github.com/vercel/next.js/blob/287ad83399fa6e90deae4ab75a5f9f762adc45e7/packages/next/src/build/swc/options.ts#L153-L155
Now what's really strange is that if I do set emotion: true in my next.config.js, then this particular feature suddenly starts working. This works even without installing @swc/plugin-emotion.
A few things on this:
@swc/plugin-emotion
, as it comes with Next by default. The plugin will be enabled if emotion
is configured in next.config.js
Yeah I was unable to replicate the issue on the latest canary release even without the swc emotion plugin installed. So I'm honestly not all to sure what the issue could be.
Doesn't sound like there is an issue aside from the documentation being lacking/confusing. At this point four different devs from my team interacted with trying to get this setup and none of us got it right, and Jesse actually got it wrong in the comments above as well.
Things that I think could be improved:
compiler.emotion
, and is not mentioned in the documentation in any way as far as I can tell. There is a precedent of frameworks enabling support for specific features when a related library is installed, so since it was working 99% of the time, I figured that simply installing emotion was all I had to do.The Emotion plugin is only needed if you want to use features like: minification, dead code elimination, source maps, and "components as selectors"
At very least the documentation could be changed to something like:
We're working to port @emotion/babel-plugin to the Next.js Compiler. Since Next.js version (insert version here), most emotion core features work out of the box. To enable full support for advanced features such as minification, dead code elimination, source maps, and components as selectors, follow these instructions:
First, update to the latest version of Next.js: npm install next@latest. Then, update your next.config.js file:
// next.config.js
module.exports = {
compiler: {
// set to true/object to enable advanced emotion features.
emotion: boolean | {
// default is true. It will be disabled when build type is production.
sourceMap?: boolean,
// default is 'dev-only'.
autoLabel?: 'never' | 'dev-only' | 'always',
// default is '[local]'.
// Allowed values: `[local]` `[filename]` and `[dirname]`
// This option only works when autoLabel is set to 'dev-only' or 'always'.
// It allows you to define the format of the resulting label.
// The format is defined via string where variable parts are enclosed in square brackets [].
// For example labelFormat: "my-classname--[local]", where [local] will be replaced with the name of the variable the result is assigned to.
labelFormat?: string,
// default is undefined.
// This option allows you to tell the compiler what imports it should
// look at to determine what it should transform so if you re-export
// Emotion's exports, you can still use transforms.
importMap?: {
[packageName: string]: {
[exportName: string]: {
canonicalImport?: [string, string],
styledBaseImport?: [string, string],
}
}
},
},
},
}
Note: You do not need to install the SWC emotion plugin manually, as it is included with Next.js by default.
Doesn't sound like there is an issue aside from the documentation being lacking/confusing. At this point four different devs from my team interacted with trying to get this setup and none of us got it right, and Jesse actually got it wrong in the comments above as well.
Things that I think could be improved:
- It's confusing/unexpected that emotion mostly works when disabled, even including features like the CSS prop which seemingly shouldn't work without having emotion support correctly enabled. This is what convinced me that I didn't need to enable
compiler.emotion
, and is not mentioned in the documentation in any way as far as I can tell. There is a precedent of frameworks enabling support for specific features when a related library is installed, so since it was working 99% of the time, I figured that simply installing emotion was all I had to do.- Strange to me that none of this appears to be documented anywhere:
The Emotion plugin is only needed if you want to use features like: minification, dead code elimination, source maps, and "components as selectors"
- Confusing that the error messages you get refer to the "the swc Emotion plugin" despite official support being present without having to install that plugin. Not sure who owns this error but if it's beyond the scope of NextJS then at least an official documentation could be added to explain what's necessary to fix the issue if you're using Next.
- No documentation seems to exist which clarifies the requirement/role of the SWC emotion plugin. I'm clearly not the only one confused by this considering that Jesse also got this wrong while trying to explain how to correctly set this up (they answered my incorrect usage by giving an example repo where they installed the SWC emotion plugin, despite that not being necessary)
At very least the documentation could be changed to something like:
Emotion
We're working to port @emotion/babel-plugin to the Next.js Compiler. Since Next.js version (insert version here), most emotion core features work out of the box. To enable full support for advanced features such as minification, dead code elimination, source maps, and components as selectors, follow these instructions:
First, update to the latest version of Next.js: npm install next@latest. Then, update your next.config.js file:
// next.config.js module.exports = { compiler: { // set to true/object to enable advanced emotion features. emotion: boolean | { // default is true. It will be disabled when build type is production. sourceMap?: boolean, // default is 'dev-only'. autoLabel?: 'never' | 'dev-only' | 'always', // default is '[local]'. // Allowed values: `[local]` `[filename]` and `[dirname]` // This option only works when autoLabel is set to 'dev-only' or 'always'. // It allows you to define the format of the resulting label. // The format is defined via string where variable parts are enclosed in square brackets []. // For example labelFormat: "my-classname--[local]", where [local] will be replaced with the name of the variable the result is assigned to. labelFormat?: string, // default is undefined. // This option allows you to tell the compiler what imports it should // look at to determine what it should transform so if you re-export // Emotion's exports, you can still use transforms. importMap?: { [packageName: string]: { [exportName: string]: { canonicalImport?: [string, string], styledBaseImport?: [string, string], } } }, }, }, }
Note: You do not need to install the SWC emotion plugin manually, as it is included with Next.js by default.
Hey man, sorry to hear the issue at hand is still present. The miscommunication around the actual need for the plugin is my bad, I didn't read through the docs well enough to notice this matter is already included inside NextJS.
Not to make excuses but I got a lot on my head with some stuff in my personal life and should have read through the docs better for a more accurate replication of the issue at hand.
It's totally okay! Not blaming you for anything :)
The issue is resolved for me. Just might be a good opportunity to improve the docs a bit.
It's totally okay! Not blaming you for anything :)
The issue is resolved for me. Just might be a good opportunity to improve the docs a bit.
Glad to hear man! đŸ˜„
So, this seems to still be an issue when feeding in a variable as the second option to styled(
as in styled('div', options)
. when I put an inline options object in as the second argument, everything works fine (as in styled('div', {})
), but if I define the options argument in a variable and then feed it in (const options ={}; styled('div', options)
), I get the error Error: Component selectors can only be used in conjunction with @emotion/babel-plugin, the swc Emotion plugin, or another Emotion-aware compiler transform.
this is in a completely fresh build with nothing but next and emotion, the swc compiler set to emotion, and the emotion-root-layout-registry set up exactly as it is in the next example repo/ @Andarist's example is in the emotion github repo.
here is a codesandbox
https://codesandbox.io/p/devbox/emotion-swc-component-selector-options-q9r6dy
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"eslint": "8.54.0",
"eslint-config-next": "^14.0.3",
"next": "^14.0.5-canary.41",
"react": "18.2.0",
"react-dom": "18.2.0",
"typescript": "5.3.2"
I think the transform for component selectors is not implemented in the swc plugin.
https://github.com/swc-project/plugins/tree/main/packages/emotion/transform
I'm sorry to say it feels like the compiler.emotion
config does more damage than good, at present I feel like I have to mark most of my components that do not need for 'use client';
with /** @jsxImportSource react */
, I'm not sure if it's the compiler option fault, or the TSConfig compilerOptions.jsxImportSource: "@emotion/react"
, I ended up disabling both and everything worked ok, so how are these 2 options supposed to be used then?
I'm trying to make SWC work with MUI/Emotionand it none of the available solutions seem to work Heres a base code https://codesandbox.io/p/devbox/frosty-lake-v6ymx4
Just ran into this moving from styled components to emotion for MUI. We were using an options object to replace the "transient prop" behavior for "$" props. Passing the object directly causes this error (only when compiling in dev mode). You can avoid the error by supplying a literal instead - but you don't actually have to rewrite all of the code for shouldForwardProp each time - instead I've discovered you can simply spread the object out into an empty object literal, so:
Instead of this:
export const transientOptions: Parameters<CreateStyled>[1] = {
shouldForwardProp: (propName: string) => !propName.startsWith("$"),
};
....
// This will cause an error with emotion/SWC
export const TimelineEvent = styled(Box, transientOptions)<{ $prop: boolean; }>` ... code which contains component selectors...`
You can just do this, which works fine:
export const TimelineEvent = styled(Box, {...transientOptions})<{ $prop: boolean; }>`... code which contains component selectors...`
Verify canary release
Provide environment information
Which area(s) of Next.js are affected? (leave empty if unsure)
SWC transpilation
Link to the code that reproduces this issue
https://codesandbox.io/p/sandbox/polished-browser-went6z
To Reproduce
The following is a minimal reproduction (used in the reproduction codesandbox):
No extra steps are required to reproduce. Simply load the codesandbox and observe the resulting error.
Describe the Bug
I'm getting the error:
When using component selectors as described in the "Targeting another emotion component" section of the emotion docs, I'm getting this error.
Expected Behavior
Since this reproduction repo uses the swc Emotion plugin, I would not expect this syntax to result in an error.
Given the example above, I would expect green text "Test" when rendering
A
insideB
.Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
No response