Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrating to emotion 10 docs unclear relating to theming, keyframes and SSR #1578

Closed
genevieveloreal opened this issue Oct 28, 2019 · 10 comments

Comments

@genevieveloreal
Copy link

Firstly, thanks to the maintainers of emotion! I'm new to emotion, having used it for approximately 3 months so far with React.

I'm hoping to get some clarification surrounding migrating from emotion 9 to 10 as this is something we're currently working towards with the code base at my work, and I've found the docs to be somewhat vague in certain areas.

Questions not covered by docs

  • Does SSR working out of the box require you to only have @emotion/core and @emotion/styled as dependencies? Would utilising vanilla emotion (or any other emotion modules other than @emotion/core and @emotion/styled) mean SSR will not work out of the box?

  • When I visit https://emotion.sh/docs/introduction under the React section, one of the bullet points states "Theming works out of the box", which I would interpret as meaning that @emotion/core includes theming functionality. However, when I then go to https://emotion.sh/docs/emotion-theming, it states that Theming is accomplished using ThemeProvider (which requires emotion-theming). I suppose my question is, does theming work out of the box with @emotion/core? And if not, it may be helpful to list the requirement for emotion-theming. I'm wondering if ThemeProvider has been replaced by anything in Emotion 10? The Migrating to Emotion 10 page doesn't mention ThemeProvider and if it can continue to be used. I can't see it within any of the code snippets on this page, so I'm unsure.

  • What functionality has been moved to @emotion/core? Does this now contain the functionality of emotion-server and emotion-theming that were previously separate modules as part of Emotion 9, or are emotion-server and emotion-theming still required?

  • Can keyframes now be imported from @emotion/core and are there any differences between using keyframes from vanilla emotion and @emotion/core?

It'd be great to clarify these points and help improve documentation for others who are new to emotion and unfamiliar with the changes between emotion 9 and 10.

@Andarist
Copy link
Member

Does SSR working out of the box require you to only have @emotion/core and @emotion/styled as dependencies? Would utilising vanilla emotion (or any other emotion modules other than @emotion/core and @emotion/styled) mean SSR will not work out of the box?

Yes, when doing SSR with vanilla emotion you have to follow this https://emotion.sh/docs/ssr#using-emotion-10-with-the-old-ssr-apis

I suppose my question is, does theming work out of the box with @emotion/core?

Yes, @emotion/core has builtin support for theming - but to make things work you have provide a theme, right? And that's done through ThemeProvider from emotion-theming. What "builtin" support for theming means is that if you wrap your application in ThemeProvider then provided theme will be available in styled interpolations & for functions given to css prop. We don't plan to drop theming support in the near future - but builtin theming has its drawbacks (and it applies to ANY css-in-js library with builtin theming, those problems are not unique for emotion). You can read more about those drawbacks here: #973

What functionality has been moved to @emotion/core?

No functionalities were moved per-se to that package. It just promotes a slightly different way of interacting with @emotion/core generated css. Mainly it promotes using jsx pragma and css prop over styled components API. We believe that styled components is somewhat unnecessary (although popular) abstraction. It has some inherent problems to such an API - things like props forwarding, using default props and similar. Those problems just don't exist when using @emotion/core APIs because it promotes using plain JavaScript over custom~ styled APIs. So the philosophy here is to just learn JS & React well, without introducing extra layer of styled-components API which is just sugar syntax with some limitations to it. @emotion/styled is very much still usable though if that's what you prefer.

Can keyframes now be imported from @emotion/core

Yes

and are there any differences between using keyframes from vanilla emotion and @emotion/core?

This is vanilla's implementation:

let keyframes = (...args) => {
let serialized = serializeStyles(args, cache.registered)
let animation = `animation-${serialized.name}`
insertWithoutScoping(cache, {
name: serialized.name,
styles: `@keyframes ${animation}{${serialized.styles}}`
})

and this the one from the @emotion/core package:
export const keyframes = (...args: *): Keyframes => {
let insertable = css(...args)
const name = `animation-${insertable.name}`
// $FlowFixMe
return {
name,
styles: `@keyframes ${name}{${insertable.styles}}`,
anim: 1,
toString() {
return `_EMO_${this.name}_${this.styles}_EMO_`
}
}
}

So they are different. The main between core and vanilla is that core is lazy and vanilla has to be eager when it comes to actually inserting styles (this applies to both keyframes and css). That's because vanilla gives u ready to use class names (as string) and it can't predict when and if you are going to use them - so it has to insert them to the DOM/CSSOM right away. With @emotion/core APIs we can postpone that work until we actually know that you are going to use it (when a component actually using those gets rendered). Having this lazy also gives us other minor advantages - such as being able to implement CacheProvider API which allows you to change emotion options (check them out here) without forcing a library user to create custom emotion's instance and spreading usage of that through the whole codebase.

It'd be great to clarify these points and help improve documentation for others who are new to emotion and unfamiliar with the changes between emotion 9 and 10.

I anything that I have described is useful and helped you to clarify things up then please consider preparing a documentation PR that would help future readers. If anything stays unclear - please just ask, I'm here to help you 😉

@Andarist
Copy link
Member

@genevieveloreal friendly 🏓 I would appreciate feedback on the given information and I'm wondering if it has helped you to understand how things are working right now.

@Andarist
Copy link
Member

I think I've answered all the questions asked in the thread and I hope it was helpful. We are working on v11 right now and some parts of the docs will be reworked slightly - so hopefully it will be harder in the future to get confused about all of those things.

@Nantris
Copy link
Contributor

Nantris commented Dec 6, 2019

@Andarist really helpful information as always!

I found this thread looking for an answer to a question on keyframes, so this seems like probably the best place to ask:

Is there any way for keyframes to access the theme object?

It wouldn't surprise me if that's is simply not possible right now, but I haven't found mention anywhere.


Edit: Also a totally unrelated question I've been wondering about if you don't mind, is there a substantial difference in performance between evaluating dynamic styles and static ones, or does it not matter? eg:

All styles inside the dynamicStyles variable:

const dynamicStyles = ({ theme }) => {
  const { myColors } = theme;
  return css`
    color: ${myColors.colorA};
    line-height: 1.5;
    margin-top: 1px;
    margin-bottom: 1px;
    flex-grow: 1;
    flex-shrink: 1;
    white-space: nowrap;
  `;
};

const StyledComponent = styled.span`
  ${dynamicStyles}
`;

Only dynamic styles inside dynamicStyles variable:

const dynamicStyles = ({ theme }) => {
  const { myColors } = theme;
  // Only dynamically changed styles inside the dynamicStyles variable
  return css`
    color: ${myColors.colorA};
  `;
};

const StyledComponent = styled.span`
    line-height: 1.5;
    margin-top: 1px;
    margin-bottom: 1px;
    flex-grow: 1;
    flex-shrink: 1;
    white-space: nowrap;
`;

@Andarist
Copy link
Member

Andarist commented Dec 7, 2019

It wouldn't surprise me if that's is simply not possible right now, but I haven't found mention anywhere.

It's not possible - it's the same case as with css function. You can only get theme from outside. Both can be called outside of the React tree so there is no way to get a theme. Or rather - there is, we could store those functions on returned values instead of serializing styles right away, but it would make certain optimizations not possible (or at least harder).

is there a substantial difference in performance between evaluating dynamic styles and static ones, or does it not matter?

Hard to answer - you'd have to benchmark this. Splitting dynamic & static is quite naturally better but the perf difference might not be worth trouble of doing this all over the place.

@Nantris
Copy link
Contributor

Nantris commented Dec 7, 2019

Thank you a lot for your helpful explanation @Andarist! That's pretty much what I figured, but it's just so much tougher to work around with keyframes since they can't be both reusable and receive the theme prop (unless I'm overlooking another possibility.) eg,

const ItemRoot = styled.div`
  ${props =>
  props.isOpen &&
  css`
    animation-iteration-count: 1;
    animation: ${keyframes` //  <<< Must be defined anew in every component that uses the animation or not use theme
      0% {
        background-color: rgba(255, 247, 20, 0.4);
      }
      100% {
        background-color: transparent;
      }`} 3s;
  `}
`

Fortunately we only have a handful to use, but it would get tough if we had dozens of cases to cover.

I'd love to run that benchmark, but will probably never find the time. If I do though, I'll share it somewhere. Thanks again @Andarist!

@Andarist
Copy link
Member

Andarist commented Dec 7, 2019

Just use JavaScript to extract this to a function 😃

const getAnimation = theme => keyframes`
  0% {
    background-color: rgba(255, 247, 20, 0.4);
  }
  100% {
    background-color: transparent;
  }
`;

const ItemRoot = styled.div`
  ${props =>
    props.isOpen &&
    css`
      animation-iteration-count: 1;
      animation: ${getAnimation(props.theme)} 3s;
    `}
`;

@Nantris
Copy link
Contributor

Nantris commented Dec 7, 2019

I tried that, but functions get stringified inside of css :(

@Andarist
Copy link
Member

Andarist commented Dec 7, 2019

Notice that getAnimation in this example gets called - it's not interpolated as is (without calling) and this should work just fine (the function should not get stringified because it wont even be visible for css - as it process things after that function gets evaluated).

@Nantris
Copy link
Contributor

Nantris commented Dec 7, 2019

Ahh! Obviously I didn't try that, and obviously it works. Thank you @Andarist!

I feel like the docs could benefit from an example like this. I know there's a project to improve the docs already, but there's a few things like this that don't really fall under any specific docs heading that exists today that might be worth including on a "Tips and Tricks" page or something.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants