emotion icon indicating copy to clipboard operation
emotion copied to clipboard

Can't clear emotion cache.

Open mctrafik opened this issue 6 months ago • 8 comments

Current behavior:

injectGlobal from @emotion/css retains injections from another emotion server!

To reproduce:

It's a server-side rendered app.

Render code:

import { getMarkupFromTree } from '@apollo/client/react/ssr';
import { cache as emotionCache, injectGlobal } from '@emotion/css';
import { CacheProvider as EmotionCacheProvider } from '@emotion/react';
import createEmotionServer from '@emotion/server/create-instance';
import type { NextFunction, Request, Response } from 'express';
import type { FC } from 'react';
import { renderToString } from 'react-dom/server';

const App: FC<{ bgColor: string }> = ({ bgColor }) => {
  injectGlobal(`body { background-color: ${bgColor}; }`);
  return <>Dummy App</>;
};

export async function renderDummy(
  request: Request,
  response: Response,
  next: NextFunction
): Promise<void> {
  const currentUrl = new URL(request.url, `${request.protocol}://${request.hostname}`);
  const bgColor = currentUrl.searchParams.get('background-color') ?? 'blue';

  const { extractCriticalToChunks, constructStyleTagsFromChunks } =
    createEmotionServer(emotionCache);

  const reactMarkup = (
    <EmotionCacheProvider value={emotionCache}>
      <App bgColor={bgColor} />
    </EmotionCacheProvider>
  );

  const markup = await getMarkupFromTree({
    tree: reactMarkup,
    renderFunction: renderToString,
  });

  const styleChunks = extractCriticalToChunks(markup);
  const styles = styleChunks.styles.map(style => {
    return { ...style, key: 'my-app' };
  });

  const emotionStyleTags = constructStyleTagsFromChunks({
    html: markup,
    styles,
  });

  const output = `<!DOCTYPE html> 
<head>
${emotionStyleTags}
</head>
<html>
<body>
${markup}
</body>
</html>
  `;

  response.setHeader('Content-Type', 'text/html');
  response.write(output);
  response.status(200);
  response.end();
}

Calling http://localhost will render text on blue background (because that's the default). Calling http://localhost/?background-color=yellow will render a yellow background Calling http://localhost again will keep rendering yellow background even though it should be blue!

Expected behavior:

It should render the background compatible with the the current invocation, and not use state cache state for global injection.

Note that I tried to make a new cache every render, i.e. const emotionCache = createEmotionCache({ key: 'marketing-web-emotion' }); but that just doesn't work. No warnings, errors, nor content.

If nothing else, it would be nice to be able to reset the cache, but that also doesn't seem possible. I tried inspecting cache's inserted and registered properties, but they don't contain globally injected styles.

Environment information:

  • react version: 18.2
  • @emotion/react version: 11.9.0

mctrafik avatar Nov 30 '23 06:11 mctrafik