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

Allow overriding functions exported by emotion/css #3226

Open
kbrooks opened this issue Jul 26, 2024 · 0 comments
Open

Allow overriding functions exported by emotion/css #3226

kbrooks opened this issue Jul 26, 2024 · 0 comments

Comments

@kbrooks
Copy link

kbrooks commented Jul 26, 2024

The problem

I work on a project that uses the css function from @emotion/css for almost all styles. We also use the stylis-rtl-plugin to transform styles to RTL ones.

// @shared/emotion/src/index.js
import createEmotion from '@emotion/css/create-instance';
import stylisRtl from 'stylis-plugin-rtl';

export let { flush, hydrate, cx, merge, getRegisteredStyles, injectGlobal, keyframes, css, sheet, cache } =
  createEmotion();

export const generateEmotion = () => {
  ({ flush, hydrate, cx, merge, getRegisteredStyles, injectGlobal, keyframes, css, sheet, cache } = createEmotion({
    stylisPlugins: document.documentElement.getAttribute('dir') === 'rtl' ? [stylisRtl] : [],
  }));
};

We call the generateEmotion function from our localization script which also sets the document.dir variable.

To make this work with have an alias defined in our webpack config to make it so all @emotion/css imports point at this file:

  resolve: {
    alias: {
      '@emotion/css$': path.resolve(basePath, 'node_modules/@shared/emotion'),
    },

(One issue with our approach is that it only works for calls to @emotion/css which are lazy-loaded instead of the initial chunk which is not something I have a solution for)

We recently started splitting up our app with module federation which has led to difficulties managing the emotion instance, which needs to be shared between all micro frontends, but this shared module configuration conflicts with our existing webpack alias.

Proposed solution

If emotion allowed overriding the default instance, we would not have to do this webpack alias solution and could instead call an overrideEmotion function to set new values to css and other functions.

I wrote a patch on our repo to add this feature, and it works:

// @flow
import createEmotion from './create-instance'

export let {
  flush,
  hydrate,
  cx,
  merge,
  getRegisteredStyles,
  injectGlobal,
  keyframes,
  css,
  sheet,
  cache
} = createEmotion({ key: 'css' })

export function overrideEmotion(emotion) {
  flush = emotion.flush;
  hydrate = emotion.hydrate;
  cx = emotion.cx;
  merge = emotion.merge;
  getRegisteredStyles = emotion.getRegisteredStyles;
  injectGlobal = emotion.injectGlobal;
  keyframes = emotion.keyframes;
  css = emotion.css;
  sheet = emotion.sheet;
  cache = emotion.cache;
}

Then the generateEmotion function above can be updated to this:

export const generateEmotion = () => {
  overrideEmotion(createEmotion({
    stylisPlugins: document.documentElement.getAttribute('dir') === 'rtl' ? [stylisRtl] : [],
  }));
};

This makes it so all calls to css use the stylis plugin and whatever other overrides you might want.

Alternative solutions

Is it possible to directly mutate the emotion cache to set new values?

Additional context

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

1 participant